fix(web): home detail-panel overflow menu, dynamic greeting, markdown summary (LUM-1759)#31412
Conversation
…ssistant/ (LUM-1753.4) These were sitting in `domains/chat/api/assistant.ts` — the runtime identity of the assistant has nothing to do with chat. It's a property of the assistant itself, queried by chat, the identity tab, contacts, intelligence, onboarding, the sync router, and several stream handlers. Misplaced since day one. Now lives at `apps/web/src/assistant/identity.ts`. The `chat` file is renamed only in its header comment — it now solely owns chat-context bootstrapping (`getChatContext`, `fetchAssistantId`). The `domains/chat/api/assistant.ts` filename stays for now to avoid churn; can be renamed in a follow-up if it bothers anyone. Import sites updated: identity-tab, use-assistant-identity-init, chat-page (two lines), chat-route-content, contacts-page, chat-utils. Cross-domain allow-list: 119 → 118 imports. Small numeric drop — the structural win is that `fetchAssistantIdentity` no longer sits in another feature's folder. Verified locally: lint, typecheck, tests all green. https://claude.ai/code/session_01JPGu4yGPTL4JoLaPuqpEW2
… (LUM-1764) Back-port of vellum-ai/vellum-assistant-platform#7468. `useAssistantAvatar()` was unconditionally fetching character traits alongside the components blob and avatar image. When an assistant has a custom avatar image, the traits file is intentionally deleted on the daemon side — so every SSE reconnect (which invalidates `SYNC_TAGS.assistantAvatar`) produced a fresh 404 on the traits endpoint. 308 of them in the platform team's local daemon log. `AvatarRenderer` only reads `traits` when there is no custom image, so the fetch was pure waste in that branch. Switch to: - Fetch components + imageUrl in parallel first. - If imageUrl is non-null, skip the traits fetch entirely. - Otherwise fall through to the original behavior. No new APIs, no behavior change for assistants without a custom image. Adds a unit test mirroring the platform PR's coverage: - skips traits fetch when image resolves - still fetches traits when no image The other half of LUM-1764 — back-porting platform#7494 (remove unused pro-upgrade-machine endpoint) — is blocked. The OSS repo still has an active caller (`compute-upgrade-card.tsx`) that needs to migrate to the unified machine-resize endpoint first. Tracking on the issue. https://claude.ai/code/session_01JPGu4yGPTL4JoLaPuqpEW2
…wn summary (LUM-1759)
Back-port of vellum-ai/vellum-assistant-platform#7467 — the only
PR from LUM-1759's set that wasn't already integrated in OSS
(7413, 7414, 7415, 7416, 7421 had already landed via earlier
home work).
Changes:
- `home-detail-panel.tsx` — replace the inline mark-as-read toggle
button with an overflow menu (`<Menu.Root>`) that contains both
"Mark as read / unread" and a new "Dismiss" action. Renames "Go
to Thread" → "Go to Convo". Adds the required `onDismiss` prop.
- `home-generic-detail.tsx` — render `item.summary` as markdown
via the new `HomeMarkdownContent` component, so feed items can
use bold/italic/links/lists/etc. for richer summaries.
- `home-markdown-content.tsx` (new) — `react-markdown` + GFM with
design-token styling tuned for the condensed detail panel.
- `home-greeting-header.tsx` — accept an optional `greeting` prop
(daemon-supplied), fall back to the existing static string.
Wraps both the avatar/greeting and the New Chat button so the
greeting can truncate cleanly on narrow widths.
- `home-page.tsx` — pass `feedQuery.data?.contextBanner?.greeting`
to the header and the new `onDismiss={handleDismissItem}` to
both mobile and desktop detail panel mounts.
The `contextBanner.greeting` field was already on the home feed
response type, so this just wires it through the UI.
Verified locally: lint, typecheck clean.
https://claude.ai/code/session_01JPGu4yGPTL4JoLaPuqpEW2
There was a problem hiding this comment.
✦ APPROVE
Value: Fills the one remaining home-feed polish gap from the platform drift audit — users get a proper overflow menu for feed item actions, long dynamic greeting text no longer clips, and markdown-formatted summaries render correctly instead of as raw syntax.
What this does: Back-ports platform PR #7467 (the only one from LUM-1759's set not yet in OSS) with three focused changes: (1) replaces the inline mark-as-read toggle with a <Menu.Root> overflow menu that also exposes "Dismiss", (2) wires feedQuery.data?.contextBanner?.greeting into HomeGreetingHeader with a static fallback, (3) swaps <Typography> for <HomeMarkdownContent> in the generic detail panel. Bundled with a clean AssistantIdentity lift out of domains/chat/ into assistant/identity.ts and the 404-suppression fix for avatar traits fetches when a custom image exists.
assistant/identity.ts refactor — the move out of domains/chat/api/assistant.ts is architecturally correct: identity is a property of the assistant, not a chat concern. Six import sites updated consistently, cross-domain allowlist updated to remove the chat entry from identity-tab.tsx. Clean.
use-assistant-avatar.ts — traits skip — changing from Promise.all([components, traits, imageUrl]) to sequential imageUrl → traits if needed is the right trade-off. The comment explains why (daemon deletes the traits file when a custom image exists, so every SSE reconnect invalidation generated a 404). The test coverage is solid — two cases: custom image skips traits call entirely, no image fetches all three.
home-detail-panel.tsx — overflow menu — Menu.Root > Menu.Trigger > Menu.Content structure matches the design library's compound pattern. MailOpen/Mail icon swap per read-state is a nice touch. align="end" keeps the dropdown from clipping on the right edge.
home-greeting-header.tsx — greeting || "Here's what's been going on" is correct (|| rather than ?? so an empty string also falls back to the static label). min-w-0 flex-1 + truncate on the <Typography> correctly handles overflow for long daemon-supplied greetings.
home-markdown-content.tsx — Two non-blocking observations:
table/thead/tbody/tr/td/thoverrides are absent; GFM tables will render with browser-default<table>styling. Unlikely in home-feed summaries but worth a follow-up if tables start appearing.- No
preoverride, so fenced code blocks get browser-default<pre>wrapping around the styled<code>. Edge case for feed content, but leaves a visual gap if a summary ever contains a code block.
CI — all 7 checks green: Lint, Type Check & Build, Test, Build, Lint, Socket PR + Project.
Vellum Constitution — Yours: the overflow menu and dynamic greeting let the assistant's curated context speak clearly, making the home feed feel like it belongs to the user rather than to the interface.
Two non-blocking observations from the vex-bot review on #31412 and #31416 (both files surfaced the same gaps): 1. **Missing element overrides** — react-markdown was falling back to browser defaults for tables and fenced code blocks. Added overrides for `pre`, `table`, `thead`, `tbody`, `tr`, `th`, `td` styled with the home feed's design tokens. Tables wrap in a horizontal-scroll container so wide tables don't blow out the condensed panel layout. 2. **target="_blank" on iOS WKWebView silently fails** — without a `WKUIDelegate createWebViewWith` implementation, the webview won't open a new tab. Route through Capacitor's `openUrl()` helper (already used elsewhere for OAuth/Stripe flows) which presents `SFSafariViewController`. Web keeps the default new-tab behavior; the `href` is preserved on both platforms so right-click → copy link still works. https://claude.ai/code/session_01JPGu4yGPTL4JoLaPuqpEW2
There was a problem hiding this comment.
✦ APPROVE (re-review at 600d2199 — prior review dismissed after fix commit)
Commit 600d2199 directly resolves both non-blocking notes from the previous review. No new concerns at HEAD.
Fix 1 — target="_blank" on iOS WKWebView ✅
handleAnchorClick correctly guards on isNativePlatform() and falls back early if href is absent. event.preventDefault() fires before void openUrl(href) — right order, no race. The void suppresses the Promise return without swallowing errors (acceptable for a UI click handler). href is preserved on the element so right-click → copy link still works on web. Clean.
Fix 2 — Missing pre and GFM table overrides ✅
pre wraps fenced code blocks with overflow-x-auto, font-mono, and color-mix(in oklab, var(--content-default) 6%, transparent) background — consistent with the design-token approach used throughout the file. The table → thead → tbody → tr → th → td chain uses border-collapse, var(--border-base) row dividers, var(--surface-lift) header bg, and wraps in a horizontal-scroll container for overflow — correct for a condensed panel layout.
Rest of PR (unchanged from prior review): ✅
Overflow menu, dynamic greeting, markdown renderer, AssistantIdentity domain lift, conditional traits fetch + tests — all previously approved, no regressions introduced.
CI — 7/7 green. ✅
Devin's review was at 99495cb7 (pre-fix commit) — retriggering for second approval.
|
Codex Review: Didn't find any major issues. 🚀 ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
Closes LUM-1759.
Summary
Back-port of
vellum-ai/vellum-assistant-platform#7467— the only PR from LUM-1759's set that wasn't already integrated in OSS. The other 5 PRs from the initial audit (#7413, #7414, #7415, #7416, #7421) had already landed via earlier home work.Three small home-feed UX upgrades:
<Menu.Root>containing both "Mark as read / unread" and a new "Dismiss" action. Renames "Go to Thread" → "Go to Convo".HomeGenericDetailnow rendersitem.summaryas markdown via a newHomeMarkdownContentcomponent (react-markdown+ GFM, styled with the same design tokens as the file-viewer markdown but with tighter spacing).HomeGreetingHeaderaccepts an optional daemon-suppliedgreetingstring; falls back to the existing static "Here's what's been going on". Wraps the avatar/greeting and New Chat button so the greeting can truncate cleanly on narrow widths.contextBanner.greetingwas already on the feed response type, just wired through the UI here.Files
src/domains/home/detail-panel/home-detail-panel.tsx— overflow menu +onDismisspropsrc/domains/home/detail-panel/home-generic-detail.tsx— render summary as markdownsrc/domains/home/detail-panel/home-markdown-content.tsx— new (react-markdown + GFM + design-token styling)src/domains/home/home-greeting-header.tsx— optionalgreetingprop with fallbacksrc/domains/home/home-page.tsx— passgreeting+onDismissVerified locally
bun run lint— 0 errors.bun run typecheck— clean.Test plan
summary, verify it renders (bold, links, lists, etc.)contextBanner.greetingfrom the daemon, verify it shows in the header (and falls back when missing)https://claude.ai/code/session_01JPGu4yGPTL4JoLaPuqpEW2
Generated by Claude Code