docs: gate the custom chat layout's empty state on an empty thread - #3579
Conversation
|
Warning Review limit reached
Next review available in: 4 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
Comment |
78071bd to
eb7d657
Compare
|
@coderabbitai review |
|
|
@coderabbitai review |
|
The Chat UI guide's "Compose a custom layout" sample drops `<Chat.Empty>`
straight into `<Chat.Root>` as the last child. `<Chat.Empty>` is a prop-driven
wrapper that renders whatever it is given and never reads the chat context, so
it never hides: after the first turn the page shows the header, the full
conversation, the composer, and then the empty-state hero with its suggestion
buttons still mounted below. The `<Chat>` preset gates its own hero on
`messages.length === 0` (controlled-chat.tsx), so only the copied sample is
broken - the docs' own custom layout renders a visibly wrong UI on first use.
Wrap the hero in `<Chat.If condition={(ctx) => ctx.isEmpty}>`, which is what
`ChatIf` and `ChatContextValue.isEmpty` exist for, and move it above the
transcript. Say in prose that `<Chat.Empty>` does not hide itself, and add the
same gate to the two `veryfront/chat` module examples that feed the API
reference.
Regression test in tests/docs/guide-code-examples.test.ts, next to the existing
"Guide: chat-ui.md" suite: it asserts the guide's custom-layout sample carries
the `<Chat.If>` gate, then renders the documented composition and asserts the
hero is absent with messages and present on a fresh thread. It fails on the
unfixed guide with "custom layout sample gates the empty state with <Chat.If>".
Found on a DX dogfood walk of veryfront.com/docs/code.
…ates CI review of the previous commit. `ban-chat-antipatterns` caps src/react/components/chat/chat/index.tsx at 278 LOC and the added `<Chat.If>` lines pushed it to 280. That module doc is a duplicate of the `veryfront/chat` example in src/chat/index.ts, which is the one the API reference is generated from - the barrel's copy produced no doc output at all - so drop the edit there rather than raise the ceiling. The remaining JSDoc additions feed src/server/handlers/dev/framework-candidates.generated.ts, which is derived from source text; regenerate it with the CI-pinned Deno 2.7.7 so `generate:manifests:check` is clean.
The barrel module doc in src/react/components/chat/chat/index.tsx still showed `<Chat.Empty>` dropped straight into `<Chat.Root>` - the exact pattern the rest of this change fixes. It was left alone earlier only because `ban-chat-antipatterns` caps that file at 278 LOC and the multi-line gate pushed it to 280. Write the gate on one line instead, so the example teaches the correct pattern and the file stays at 278 LOC. The barrel's copy still produces no API-reference output (the reference renders the `src/chat/index.ts` example), so docs/api-reference is unchanged; only the derived framework-candidates manifest picks up the new comment tokens, regenerated with the CI-pinned Deno 2.7.7.
3b9f69d to
6e49962
Compare
|
Rebased onto current One extra commit on top of the original two:
That barrel copy still produces no API-reference output (the reference renders CI note: |
Symptom
Found on a DX dogfood walk of https://veryfront.com/docs/code.
The Chat UI guide's "Compose a custom layout" sample was pasted verbatim into
app/custom-chat/page.tsx. After sending one message and getting a tool-callingreply, the page renders: header, the full conversation, the composer — and then,
below the composer, the empty-state hero
What can I help with?with itsExplain React hooks/Write a regexsuggestion buttons still mounted.The guide's own custom-layout sample renders a visibly broken UI on first use,
and "Verify it worked" only said "custom layouts keep the message list and
composer wired to the same AG-UI stream", so nothing told the reader this was
wrong.
Root cause
ChatEmpty(src/react/components/chat/chat/composition/chat-empty.tsx) is aprop-driven wrapper around
ChatEmptyState.*. It never reads the chat contextand has no self-hiding behavior — it renders whatever it is given, always.
The
<Chat>preset gates its own hero externally:<Chat.Root>already publishesisEmptyon the context(
chat-root.tsx:157), and<Chat.If>exists precisely to read it — but thedocumented custom layout used neither. So the composition path had everything it
needed to self-hide and the sample simply never asked for it.
Fix
Wrap the hero in
<Chat.If condition={(ctx) => ctx.isEmpty}>and move it abovethe transcript, and state in prose that
<Chat.Empty>does not hide itself andthat a custom layout owns that decision. Add a "Verify it worked" bullet that
actually catches the bug.
The same ungated pattern shipped in the
veryfront/chatmodule example thatgenerates the API reference's "Custom layout (composition)" block
(
src/chat/index.ts), so that gets the gate too, andChatEmpty's own JSDoc —which is the description rendered in
docs/api-reference/veryfront/chat.md—now says it never hides itself.
docs/api-reference/veryfront/chat.mdis theregenerated
deno task docsoutput (Deno 2.7.7, matching.github/actions/setup-deno), not hand-edited, as issrc/server/handlers/dev/framework-candidates.generated.ts, which is derivedfrom source text and picks up the new comment tokens.
No runtime behavior changes: this is documentation plus JSDoc.
Regression test
tests/docs/guide-code-examples.test.ts, inside the existingdescribe("Guide: chat-ui.md")suite — that file is where documented guideexamples are already exercised against the real public API, and the guide source
of truth is
docs/guides/chat-ui.mdin this repo (veryfront-docsdocs/code/guides/**is a synced copy of it).The test does both halves:
docs/guides/chat-ui.mdand asserts the custom-layout sample wraps<Chat.Empty>in<Chat.If condition={(ctx) => ctx.isEmpty}>;renderToStringand asserts thehero and its suggestions are absent with two messages, the transcript is
still present, and the hero is present on an empty thread.
Confirmed red before the fix, for the right reason:
Green after, together with
tests/docs/(51 passed) andsrc/react/components/chat/(144 passed).scripts/docs/generate-api-reference.test.tspasses under the CI-pinned Deno 2.7.7.
Follow-up (not in this PR)
The published copy at
veryfront-docs/docs/code/guides/chat-ui.mdcarries thesame sample and is refreshed from this repo by
update-reference.yml; a matchingPR is opened there so the live page is corrected before the next sync.