Repository navigation
feat(apollo-vertex): add MessageThread pattern - #1549
Conversation
Dependency License Review
License distribution
Excluded packages
|
There was a problem hiding this comment.
🟡 Changes recommended
Batched updates leave some incoming messages collapsed, and expanding or collapsing a message replaces the focused control without restoring keyboard focus.
2 open issues
What changed in this PR
Adds Apollo Vertex’s MessageThread pattern, completing the conversation detail view introduced by the Inbox pattern in #1528.
Changes:
- Adds message and thread headers, expandable history, per-message slots, localized labels, and unit tests.
- Registers and exports the pattern with documentation and an interactive reply demo.
- Updates the Inbox demo to display multi-message conversations.
| File | Description |
|---|---|
packages/apollo-vertex/tsconfig.json |
Adds the message-thread import alias. |
packages/apollo-vertex/skills/vertex-component-catalog/SKILL.md |
Adds usage guidance to the component catalog. |
packages/apollo-vertex/registry/message-thread/message-thread.tsx |
Implements the thread, header, and expansion state. |
packages/apollo-vertex/registry/message-thread/message-thread.test.tsx |
Tests rendering, ordering, expansion, and controlled behavior. |
packages/apollo-vertex/registry.json |
Registers the pattern and its dependencies. |
packages/apollo-vertex/locales/en.json |
Adds English message-header and collapse labels. |
packages/apollo-vertex/entries/index.ts |
Exports the new components and types. |
apps/apollo-vertex/templates/MessageThreadTemplate.tsx |
Adds an interactive conversation and reply demo. |
apps/apollo-vertex/templates/InboxTemplate.tsx |
Displays selected conversations using MessageThread. |
apps/apollo-vertex/content/docs/patterns/meta.json |
Adds the pattern to documentation navigation. |
apps/apollo-vertex/content/docs/patterns/message-thread.mdx |
Documents installation, usage, slots, and API. |
apps/apollo-vertex/content/docs/patterns/inbox.mdx |
Links to MessageThread for conversation details. |
Review effort: Balanced
📊 Coverage + size by packagePer-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.
"Coverage" is each package's own |
Storybook visual diff✅ No stories are affected by this PR's changes; nothing to compare. Logs Updated (PT): Nov 12, 2026, 05:37:17 AM |
8e8925f to
620c581
Compare
There was a problem hiding this comment.
Looks:
Its weird I can click the row to open but not to close? The component feels not really fleshed out TBH
Docs:
The usage in the docs is also weird - it's referencing some "conversation" which isnt really there? Can we instead use the real props. The fact we are mapping them already feels weird
Components:
Basically EVERYTHING is just a react node - can we not have a better interface? At this point it's not really a proper generic component - it's just a "whatever you wanna drop in goes"?
Looks: In it's expanded state it's not really a row anymore. I can tweak it a bit so there's a more compact e-mail header that feels like a somewhat stable toggle for expand/collapsed states. Docs: Yeah, I can replace this hypothetical conversation object with just straight up values for the props. Components: All of the slots aren't great. While porting I pressed on making things like status indications and custom elements as flexible as possible, but this is a bit too loose. Things like To summarize, I'll go through the props and see what really needs to be a react node. Right now I think only |
620c581 to
63ce76d
Compare
59e3486 to
ea54257
Compare
|
@ruudandriessen I mainly cleaned up the interface quite a bit. It was sloppy to rely on Otherwise I created a generic |
ea54257 to
becd96d
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Translation interpolation HTML-escapes recipient names before React renders them as text, causing special characters to appear as literal HTML entities in message details.
1 open issue
1 resolved since last review
Review effort: Balanced
There was a problem hiding this comment.
🔵 Needs a closer look
Recipient names containing special characters are incorrectly displayed as literal HTML entities because i18next interpolation escaping remains enabled for text already safely rendered by React.
No open issues 🎉
1 resolved since last review
Review effort: Balanced
A label, a click handler and an optional disabled flag and icon, for components that take a list of things the user can do. How the actions render stays up to each component. Co-authored-by: Cursor <cursoragent@cursor.com>
A conversation of e-mail style messages, extracted from the supplier communications thread. The newest message starts expanded, older ones collapse to sender, subject and an excerpt, and each message header expands and collapses it. Messages appended later open, also when several arrive at once, and a thread that mounts empty starts once its first messages load. A message takes a typed notice and a footer, and MessageThreadHeader shows a title, a status badge and a meta line. Notices, messages and the header take Action lists, shown as buttons with the first as primary. Co-authored-by: Cursor <cursoragent@cursor.com>
The demo lists conversations and opens the selected one as a MessageThread in the detail pane. Co-authored-by: Cursor <cursoragent@cursor.com>






Summary
Adds
MessageThreadto Apollo Vertex: an e-mail style conversation, extracted from the supplier communications thread. Follow-up to #1528.Thread structure
The latest message starts expanded. Older ones collapse to sender, subject and a one-line excerpt. The header is one button that stays mounted in both states, so focus never moves. A single-message thread is always expanded and has no toggle.
Interface
Messages are plain data. The component owns layout and UI states. Only
footertakes a React node (e.g. a reply form). Everything else is typed so consumers describe intent, not markup:bodyis plain text and keeps line breaks.noticeisinfo|warning|error. Collapsed: badge. Expanded: alert with its actions.MessageThreadHeadertakestitle,badge,metaandactions.Expansion is designed for several use cases without extra branching:
[]then loading data expands only the latest.key={selectedId}resets expansion per conversation.expandedIds/onExpandedChange.order="oldest-first".Shared
ActionAction { label, onClick, disabled?, icon? }lives inlib/action.tsand is exported from the package root. It describes something the user can do; rendering stays up to the consuming component.MessageThread uses it for notice actions, message actions and header actions (first = primary button). Other components with the same shape today (AI chat message actions, solution-tests buttons, filter options) can adopt it later without inventing another type.
Also: the Inbox demo opens conversations as a thread.