feat(a2ui): publish preview payloads#2743
Conversation
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (15)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (11)
📝 WalkthroughWalkthroughServer uploads validated A2UI messages to Supabase Storage and returns preview URLs in SSE done events; the playground records and persists those URLs, supports URL-based render/init flows, can publish payloads from the client when enabled, and updates preview UI/QR/styling and docs. ChangesA2UI Payload Publishing and Preview URLs
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
packages/genui/a2ui-playground/src/hooks/useConversation.ts (1)
453-540: 💤 Low valueConsider whether
snapshotPreviewPayloadUrlsparameter is necessary.The
RecordTurnInputinterface accepts bothpreviewPayloadUrls(for the assistant message) andsnapshotPreviewPayloadUrls(for the conversation snapshot). This allows the caller to specify different URLs for the message vs. the snapshot, but the actual downstream usage in AIChatPage (line 1237-1244 context) only passespreviewPayloadUrls, neversnapshotPreviewPayloadUrls.Unless there's a planned use case for independently controlling snapshot URLs, consider simplifying by removing
snapshotPreviewPayloadUrlsand usingpreviewPayloadUrlsfor both the message and the snapshot (lines 475-477 would becomeinput.previewPayloadUrls ?? null).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/genui/a2ui-playground/src/hooks/useConversation.ts` around lines 453 - 540, RecordTurnInput's separate snapshotPreviewPayloadUrls parameter appears unused; remove snapshotPreviewPayloadUrls from the RecordTurnInput type and callers and unify logic in recordTurn (function recordTurn in useConversation.ts) to set nextPreviewPayloadUrls = input.previewPayloadUrls ?? null (replace the current input.snapshotPreviewPayloadUrls ?? input.previewPayloadUrls ?? null), then update any call sites (e.g., where recordTurn is invoked from AIChatPage) to stop passing snapshotPreviewPayloadUrls and only provide previewPayloadUrls so message and snapshot share the same URLs.packages/genui/a2ui-playground/src/pages/AIChatPage.tsx (1)
63-66: ⚡ Quick winReuse the shared
PreviewPayloadUrlstype instead of redefining it locally.This duplicates a persisted contract and can drift over time; import the existing type from
src/storage/types.ts.♻️ Proposed refactor
import { useConversation } from '../hooks/useConversation.js'; import type { ModelChatMessage } from '../hooks/useConversation.js'; +import type { PreviewPayloadUrls } from '../storage/types.js'; import { useResizablePanels } from '../hooks/useResizablePanels.js'; @@ -interface PreviewPayloadUrls { - messagesUrl: string; - actionMocksUrl?: string; -} - interface ProviderSettings {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/genui/a2ui-playground/src/pages/AIChatPage.tsx` around lines 63 - 66, The local interface PreviewPayloadUrls defined in AIChatPage.tsx duplicates the shared persisted contract; remove the local declaration and import the existing PreviewPayloadUrls type from the shared module (src/storage/types.ts), then update any usages in AIChatPage.tsx to reference the imported type (e.g., PreviewPayloadUrls) so the file relies on the single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/genui/a2ui-playground/src/components/PreviewPanel.tsx`:
- Around line 319-328: The current guard clears render state and returns when
previewSource.demoId, previewSource.messagesUrl, and useClientPayloadStore are
all falsy, which also discards inline preview messages; change the logic so that
lack of URL publishing only clears sharing/QR state (call setRenderShareUrl('')
and setLynxDevUrl('')) but does not clear/return if inline messages exist—check
previewSource.messages (or messages.length === 0) and only setRenderUrl('') and
return when there are truly no inline messages and no
demoId/useClientPayloadStore/messagesUrl; update the conditional around
setRenderUrl, setRenderShareUrl, setLynxDevUrl to preserve inline rendering
while degrading only sharing behavior.
In `@packages/genui/a2ui-playground/src/pages/DemosPage.tsx`:
- Around line 342-357: The async callback from publishA2UIPayloadForPreview can
apply stale UI state; to fix, add a request-sequencing guard: capture a local
sequence id (from a useRef counter like publishSeqRef) or use an AbortController
before calling publishA2UIPayloadForPreview, include the signal if supported,
then in the .then/.catch/.finally handlers check that the sequence id still
matches the latest (or that the controller was not aborted) before calling
setPreviewInput, setPreviewRenderKey, setError, or setIsPublishingPayload;
reference the existing publishA2UIPayloadForPreview call and the state setters
(setPreviewInput, setPreviewRenderKey, setError, setIsPublishingPayload) and the
inputs (committed.parsed, currentScenario) when implementing the guard.
In `@packages/genui/a2ui-playground/src/utils/renderUrl.ts`:
- Around line 43-53: The current branch that handles init.messagesUrl skips
building the canonical base64 init payload and only sets individual query params
(messagesUrl/actionMocksUrl), breaking the renderUrl contract; update the
renderUrl flow so that even when init.messagesUrl is present you still include
the base64-encoded init payload (use encodeBase64Url(JSON.stringify(...)) and
url.searchParams.set with the same init payload query param used elsewhere)
while optionally also setting messagesUrl/actionMocksUrl as metadata; ensure you
reference the same encodeBase64Url, init object and url.searchParams.set calls
so the preview iframe always receives the base64 initData.
---
Nitpick comments:
In `@packages/genui/a2ui-playground/src/hooks/useConversation.ts`:
- Around line 453-540: RecordTurnInput's separate snapshotPreviewPayloadUrls
parameter appears unused; remove snapshotPreviewPayloadUrls from the
RecordTurnInput type and callers and unify logic in recordTurn (function
recordTurn in useConversation.ts) to set nextPreviewPayloadUrls =
input.previewPayloadUrls ?? null (replace the current
input.snapshotPreviewPayloadUrls ?? input.previewPayloadUrls ?? null), then
update any call sites (e.g., where recordTurn is invoked from AIChatPage) to
stop passing snapshotPreviewPayloadUrls and only provide previewPayloadUrls so
message and snapshot share the same URLs.
In `@packages/genui/a2ui-playground/src/pages/AIChatPage.tsx`:
- Around line 63-66: The local interface PreviewPayloadUrls defined in
AIChatPage.tsx duplicates the shared persisted contract; remove the local
declaration and import the existing PreviewPayloadUrls type from the shared
module (src/storage/types.ts), then update any usages in AIChatPage.tsx to
reference the imported type (e.g., PreviewPayloadUrls) so the file relies on the
single source of truth.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: bba65d5b-16e4-4164-8abb-c8252e980513
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (14)
packages/genui/a2ui-playground/examples/README.mdpackages/genui/a2ui-playground/rsbuild.config.tspackages/genui/a2ui-playground/src/components/PreviewPanel.tsxpackages/genui/a2ui-playground/src/hooks/useConversation.tspackages/genui/a2ui-playground/src/pages/AIChatPage.tsxpackages/genui/a2ui-playground/src/pages/DemosPage.tsxpackages/genui/a2ui-playground/src/storage/types.tspackages/genui/a2ui-playground/src/styles.csspackages/genui/a2ui-playground/src/utils/renderUrl.tspackages/genui/server/app/a2ui/action/stream/route.tspackages/genui/server/app/a2ui/payload-publisher.tspackages/genui/server/app/a2ui/payload/route.tspackages/genui/server/app/a2ui/stream/route.tspackages/genui/server/package.json
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will not alter performance
Comparing Footnotes
|
9a7c399 to
8b02a26
Compare
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a per-conversation "Share" action that builds and copies a durable preview URL, shows success/failure toasts, and is disabled for disabled or renaming items. * Sharing reuses or persists preview payloads so links remain valid when in-memory data is unavailable. * **Refactor** * Centralized preview-payload publishing into a shared utility used by playback and sharing flows. * **Documentation** * Added playground README with setup and preview-sharing instructions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> ## What Adds a **Share** action to every conversation in the GenUI playground's Create page. Clicking it copies a durable, Supabase-backed `render.html` link for that conversation's generated UI to the clipboard, with the existing copy toast — the same artifact `PreviewPanel` already produces via "Copy render URL", now available per conversation. ## Why Conversations could be renamed and deleted, but not shared. The server already publishes each turn's A2UI payload to Supabase Storage (#2743) and the playground persists the resulting `previewPayloadUrls` on each conversation snapshot, so a durable shareable link is essentially already available — it just wasn't surfaced. ## How it works `handleShareConversation(id)` resolves a durable `messagesUrl`: 1. Active conversation → freshest published URLs already in component state. 2. Otherwise → `previewPayloadUrls` persisted on the conversation snapshot (or the most recent message that has them). 3. Fallback → if no stored URL yet, publish the raw A2UI messages on demand via `POST /a2ui/payload`. `buildRenderUrl()` then turns the `messagesUrl` into the shareable link. ## Changes - **New** `src/utils/publishPayload.ts` — shared client→Supabase publish helper, extracted from `DemosPage`. - `ConversationListPanel.tsx` — `onShare` prop + a **Share** pill (reuses existing styling). - `AIChatPage.tsx` — `handleShareConversation` + wiring. - `DemosPage.tsx` — refactored to import the shared helper. ## Checklist - [x] Tests updated (or not required). _(not required)_ - [x] Documentation updated (or not required). _(not required)_ - [x] Changeset added... (or not required). _(not required — `a2ui-playground` is private; changesets skip private packages)_
Summary by CodeRabbit
New Features
Improvements
Checklist