Skip to content

feat(a2ui-playground): add per-conversation share button#2770

Merged
PupilTong merged 1 commit into
lynx-family:mainfrom
PupilTong:claude/trusting-heyrovsky-9fcd5b
Jun 3, 2026
Merged

feat(a2ui-playground): add per-conversation share button#2770
PupilTong merged 1 commit into
lynx-family:mainfrom
PupilTong:claude/trusting-heyrovsky-9fcd5b

Conversation

@PupilTong
Copy link
Copy Markdown
Collaborator

@PupilTong PupilTong commented Jun 2, 2026

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.

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.tsxonShare prop + a Share pill (reuses existing styling).
  • AIChatPage.tsxhandleShareConversation + wiring.
  • DemosPage.tsx — refactored to import the shared helper.

Checklist

  • Tests updated (or not required). (not required)
  • Documentation updated (or not required). (not required)
  • Changeset added... (or not required). (not required — a2ui-playground is private; changesets skip private packages)

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 2, 2026

⚠️ No Changeset found

Latest commit: dfae83e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds end-to-end conversation sharing: a shared publish utility for durable preview URLs, a Share button in the conversation list, a share handler in AIChatPage that loads/publishes snapshots and copies a render URL, and DemosPage updated to use the shared publisher.

Changes

Conversation sharing and durable URL generation

Layer / File(s) Summary
Shared payload publishing utility with endpoint detection
packages/genui/a2ui-playground/src/utils/publishPayload.ts
PublishedPayload interface and publishA2UIPayload() detect dev vs. production endpoints, POST messages and action mocks to GenUI, parse and validate the response for messagesUrl, and return durable URLs or throw on failure.
Share button UI in conversation list
packages/genui/a2ui-playground/src/components/ConversationListPanel.tsx
ConversationListPanelProps adds onShare callback, component destructures it, and renders a Share action button per conversation item that invokes the callback and is disabled when the panel is disabled or the item is being edited.
Share conversation handler and wiring in AIChatPage
packages/genui/a2ui-playground/src/pages/AIChatPage.tsx
Adds imports loadConversation and publishA2UIPayload; implements handleShareConversation to resolve or publish preview payload URLs from memory or snapshot, build a render URL, copy it to the clipboard, and show success/error toast; wires handler to ConversationListPanel.onShare.
DemosPage refactor to adopt shared payload utility
packages/genui/a2ui-playground/src/pages/DemosPage.tsx
Imports shared publishA2UIPayload, moves playback types earlier, removes local dev-host detection and publishA2UIPayloadForPreview, and updates handleRender to call the shared utility.
Playground README
packages/genui/a2ui-playground/README.md
New README documenting startup, server env vars (including Supabase and PEXELS), endpoint override, and npm/pnpm scripts for the playground.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • Sherry-hue
  • HuJean

Poem

🐰 I found a link beneath the thyme,
I wrapped our chat in a durable rhyme.
Click Share and watch it leap,
A copied URL to keep—
Hooray, the conversation hops in time!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(a2ui-playground): add per-conversation share button' accurately and specifically describes the main change: adding a Share button to conversations in the GenUI playground.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 2, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/genui/a2ui-playground/src/pages/AIChatPage.tsx (1)

188-197: 💤 Low value

Consider extracting isDevHost to the shared utility.

This function is now duplicated verbatim in utils/publishPayload.ts. You could export it from there and import it here for consistency, reducing the maintenance surface.

🤖 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 188 -
197, Extract the duplicated isDevHost logic into the shared utility by exporting
the existing isDevHost function from utils/publishPayload.ts and replacing the
local definition in AIChatPage.tsx with an import of that exported function;
update the AIChatPage.tsx file to import { isDevHost } from the utils module,
remove the inline isDevHost function, and ensure any other files using the
duplicate (e.g., utils/publishPayload.ts) keep a single exported implementation
to avoid duplication.
🤖 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.

Nitpick comments:
In `@packages/genui/a2ui-playground/src/pages/AIChatPage.tsx`:
- Around line 188-197: Extract the duplicated isDevHost logic into the shared
utility by exporting the existing isDevHost function from
utils/publishPayload.ts and replacing the local definition in AIChatPage.tsx
with an import of that exported function; update the AIChatPage.tsx file to
import { isDevHost } from the utils module, remove the inline isDevHost
function, and ensure any other files using the duplicate (e.g.,
utils/publishPayload.ts) keep a single exported implementation to avoid
duplication.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 85944996-5b71-4ec3-ba6d-8523d155a646

📥 Commits

Reviewing files that changed from the base of the PR and between 3794d0c and a934e5d.

📒 Files selected for processing (4)
  • packages/genui/a2ui-playground/src/components/ConversationListPanel.tsx
  • packages/genui/a2ui-playground/src/pages/AIChatPage.tsx
  • packages/genui/a2ui-playground/src/pages/DemosPage.tsx
  • packages/genui/a2ui-playground/src/utils/publishPayload.ts

@PupilTong PupilTong force-pushed the claude/trusting-heyrovsky-9fcd5b branch from a934e5d to 33b4f0a Compare June 2, 2026 09:53
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Jun 2, 2026

Merging this PR will degrade performance by 14.75%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 82 untouched benchmarks
⏩ 26 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
transform 1000 view elements 40.2 ms 47.2 ms -14.75%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing PupilTong:claude/trusting-heyrovsky-9fcd5b (dfae83e) with main (af38400)2

Open in CodSpeed

Footnotes

  1. 26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (8895853) during the generation of this report, so af38400 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/genui/a2ui-playground/src/pages/AIChatPage.tsx (2)

1810-1818: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reuse the existing history reconstruction fallback before giving up.

If a stored conversation has neither previewPayloadUrls nor snapshot.previewMessages, Share just falls through to failure, even though the page can already rebuild preview data from message history via buildPreviewMessagesFromHistory(...) on Lines 1206-1208. That means older/incomplete snapshots can still render after opening the conversation but cannot be shared directly from the list. Please fall back to reconstructing from record.messages before returning showCopyToast(false).

🤖 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 1810 -
1818, If neither urls.messagesUrl nor snapshot.previewMessages produce
fallbackMessages, call the existing
buildPreviewMessagesFromHistory(record.messages) to reconstruct preview messages
from history (the same logic used earlier) and assign its result to
fallbackMessages before falling back to showCopyToast(false); update the branch
around urls.messagesUrl / fallbackMessages checks (referencing urls.messagesUrl,
snapshot.previewMessages, fallbackMessages, record.messages, and
buildPreviewMessagesFromHistory) so reconstructed previews are used for sharing
when available.

1786-1790: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't trust the cached payload URL for the active preview unconditionally.

For the active conversation, this branch assumes latestPreviewPayloadUrlsRef.current still matches the preview currently on screen. It doesn't after local-only replacements like handleLoadExample() on Line 1731, which updates latestPreviewMessagesRef but never clears the payload URL ref. In that state, Share copies the previous turn's durable URL instead of the example the user is looking at. Clear the cached URLs whenever preview content is replaced without a publish, or force this path to republish fallbackMessages when the active preview is known to be unpublished.

🤖 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 1786 -
1790, The active-preview branch uses latestPreviewPayloadUrlsRef.current
unconditionally causing stale durable URLs after local-only updates (e.g.,
handleLoadExample) which updates latestPreviewMessagesRef but never clears
payload URLs; update the logic so that handlers that perform local-only preview
replacements (handleLoadExample and any similar functions that mutate
latestPreviewMessagesRef) also clear latestPreviewPayloadUrlsRef.current (set to
null/undefined) and/or mark the preview as unpublished, and in the id ===
activeId branch (where urls and fallbackMessages are set) detect a
missing/cleared latestPreviewPayloadUrlsRef.current and either trigger the
existing republish/generate-durable-url routine (e.g., call
publishPreview/publishPayload/generateDurableUrl with fallbackMessages) before
assigning urls or fall back to forcing republish of fallbackMessages so Share
never uses a stale URL; update references in AIChatPage.tsx to
latestPreviewPayloadUrlsRef, latestPreviewMessagesRef, handleLoadExample, and
the id === activeId branch accordingly.
🤖 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.

Outside diff comments:
In `@packages/genui/a2ui-playground/src/pages/AIChatPage.tsx`:
- Around line 1810-1818: If neither urls.messagesUrl nor
snapshot.previewMessages produce fallbackMessages, call the existing
buildPreviewMessagesFromHistory(record.messages) to reconstruct preview messages
from history (the same logic used earlier) and assign its result to
fallbackMessages before falling back to showCopyToast(false); update the branch
around urls.messagesUrl / fallbackMessages checks (referencing urls.messagesUrl,
snapshot.previewMessages, fallbackMessages, record.messages, and
buildPreviewMessagesFromHistory) so reconstructed previews are used for sharing
when available.
- Around line 1786-1790: The active-preview branch uses
latestPreviewPayloadUrlsRef.current unconditionally causing stale durable URLs
after local-only updates (e.g., handleLoadExample) which updates
latestPreviewMessagesRef but never clears payload URLs; update the logic so that
handlers that perform local-only preview replacements (handleLoadExample and any
similar functions that mutate latestPreviewMessagesRef) also clear
latestPreviewPayloadUrlsRef.current (set to null/undefined) and/or mark the
preview as unpublished, and in the id === activeId branch (where urls and
fallbackMessages are set) detect a missing/cleared
latestPreviewPayloadUrlsRef.current and either trigger the existing
republish/generate-durable-url routine (e.g., call
publishPreview/publishPayload/generateDurableUrl with fallbackMessages) before
assigning urls or fall back to forcing republish of fallbackMessages so Share
never uses a stale URL; update references in AIChatPage.tsx to
latestPreviewPayloadUrlsRef, latestPreviewMessagesRef, handleLoadExample, and
the id === activeId branch accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ea9dbaea-065e-4f50-b381-d32570105c98

📥 Commits

Reviewing files that changed from the base of the PR and between e9b2d50 and a7474ba.

📒 Files selected for processing (2)
  • packages/genui/a2ui-playground/src/pages/AIChatPage.tsx
  • packages/genui/a2ui-playground/src/utils/publishPayload.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/genui/a2ui-playground/src/utils/publishPayload.ts

Sherry-hue
Sherry-hue previously approved these changes Jun 3, 2026
Rebased onto upstream/main and re-integrated the Share action into the new
icon-button system (lynx-family#2776): a Share2 icon Button in the conversation list that
copies a durable Supabase-backed render link. Includes the shared publishPayload
util (dedupes DemosPage), the snapshot/history URL resolution, the stale-URL
fix on example load, and the playground README.
@PupilTong PupilTong force-pushed the claude/trusting-heyrovsky-9fcd5b branch from 5c4aaae to dfae83e Compare June 3, 2026 09:14
@PupilTong PupilTong requested a review from Sherry-hue June 3, 2026 10:32
@PupilTong PupilTong merged commit b30a5c5 into lynx-family:main Jun 3, 2026
72 of 76 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants