feat(web): History — Pin & Replay, plus two history-status fixes (#1438)#1441
feat(web): History — Pin & Replay, plus two history-status fixes (#1438)#1441cliffhall wants to merge 15 commits into
Conversation
…ns (#1439) `extractStatus` derived the history status badge purely from whether a `response` was attached, so a fire-and-forget notification (no id, no response ever) — and any unmatched standalone response — was labelled "Pending" forever. The pending → OK/Error lifecycle only applies to request entries (messageLogState attaches the response by JSON-RPC id), so scope the status to `direction === "request"` and render no request-style badge for notifications/responses. The method badge already labels them. Part of the History-screen work on #1438. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… in history (#1440) MessageTrackingTransport.send only tracked outgoing requests, so the client's response to a server→client request (roots/list, sampling, elicitation) was never recorded. The inbound request entry never got its response folded in, leaving it stuck "Pending" with no response body. Make send symmetric with onmessage: track outgoing responses (by id + result/error) as well as outgoing requests. The response now correlates to its request entry, which resolves to OK/Error with the body. Outgoing notifications remain untracked (separate gap). Part of the History-screen work on #1438. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both HistoryEntry actions were rendered but stubbed to todoNoop in App. - Pin: App now owns a session-scoped Set<string> of pinned entry ids, toggled by onTogglePinHistory and passed down as pinnedHistoryIds. HistoryListPanel already sorts pinned entries to the top. The set resets with the rest of the per-screen state on disconnect/server-switch. - Replay: onReplayHistory re-issues the entry's original request by method (tools/call → callTool, prompts/get → getPrompt, resources/read → readResource). The call flows through InspectorClient → tracked transport → message log, so the fresh request+response surface as a new History entry (history-local) without touching the Tools/Prompts/ Resources panels. Unsupported methods / a removed tool surface a toast. Tests: pin toggle propagation, replay dispatch for each supported method, unsupported-method and missing-tool toasts. Closes #1438. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaying a tools/list entry reported "Replay isn't supported". Extend replayHistoryRequest beyond the call-style requests to the read/discovery methods, re-issuing each via its InspectorClient method (preserving the pagination cursor): - tools/list → listTools, prompts/list → listPrompts, resources/list → listResources, resources/templates/list → listResourceTemplates, ping → ping. Tests: tools/list replay (cursor preserved) and an unsupported-method toast (logging/setLevel). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ttons - Add tasks/list to the replayable set (re-issued via listRequestorTasks), completing the client-issued */list methods. - Reverse the HistoryEntry actions to Pin then Replay, and hide Replay for entries whose method can't be replayed. - Introduce a single source of truth — REPLAYABLE_HISTORY_METHODS / isReplayableHistoryMethod in historyUtils — used by HistoryEntry to show/hide the button and by App's replayHistoryRequest to gate dispatch, so the two can't drift. Tests: tasks/list replay, Replay hidden for a non-replayable method, and Pin-before-Replay ordering. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1437) A dual-state badge at the top-left of each entry shows which way it traveled: "client → server" (green) for inspector-originated, "client ← server" (yellow) for server-originated. - New shared element MessageDirectionBadge (Elements). - History: MessageEntry gains an `origin` ("client" | "server") set at tracking time — MessageTrackingTransport tags `send` as client and `onmessage` as server, threaded through the track callbacks. HistoryEntry maps origin → badge. (direction stays the request/response/notification message-type used for response correlation; origin is the flow.) - Network: fetches are always inspector-originated, so NetworkEntry renders the badge as outgoing. Tests + stories for the badge; HistoryEntry direction tests; transport test asserts the origin argument. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… badge Yellow + green read as caution/ok status; purple vs green reads as direction. Incoming (server → client) is now violet; outgoing stays green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "Pinned Requests (N)" and "History (N)" section headers are now clickable toggle buttons that expand/collapse their entries — styled like the LogControls level toggles (UnstyledButton listItem variant with the active background) and wrapping the entries in a Collapse. Both default open and collapse independently. Tests assert the per-section aria-expanded toggling and independence. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
History, Network, and Task cards now use a shared ExpandToggle ActionIcon instead of the "Expand"/"Collapse" text button: LuArrowDownToLine when collapsed (expand), LuArrowUpFromLine when expanded (collapse). The aria-label stays "Expand"/"Collapse" so the control reads the same. - New shared element ExpandToggle (+ test + stories). - HistoryEntry: actions split into a left group (Pin/Replay) with the toggle pushed right via space-between. - NetworkEntry / TaskCard: drop their now-unused SubtleButton const. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the Pin/Unpin text button with a shared PinToggle ActionIcon (TiPinOutline when unpinned, TiPin when pinned; aria-label stays Pin/Unpin). Move it to the right action group, just left of the expand/collapse toggle — Replay stays on the left. - New shared element PinToggle (+ test + stories). - HistoryEntry action row: Replay left; Pin + expand toggle right. - Drop the now-unused formatPinLabel helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each section header now shows Clear and Export links on the right, but only when both sections are present (a single section is already covered by the panel-level Clear/Export). They act on just that section's entries: - Clear: removes that section's entries by pin membership (clearing the Pinned section also drops the now-stale pinned id set). - Export: downloads just that section's entries (inspector-history-pinned/-unpinned-...json). Threaded onClearSection/onExportSection App → InspectorView → HistoryScreen → HistoryListPanel; App computes each section from messages + pinned ids. Extracted a CollapsibleSection subcomponent and a SectionActions links group. Extended ExportKind with history-pinned/history-unpinned. Tests cover both-sections visibility gating and per-section dispatch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a "Filter by Message Direction" section to HistoryControls, modeled on LogControls' "Filter by Level": a Select/Deselect All control plus two listItem toggles — "client → server" and "client ← server" — that show or hide entries by origin. - HistoryUiState gains visibleDirections (Record<MessageOrigin, boolean>), defaulting to both visible; persists with the other per-screen state. - HistoryScreen wires the toggles (single + all) through onUiChange and passes the filter to HistoryListPanel, where matchesFilters drops entries whose direction is off (entries without a recorded origin are never filtered out). Tests cover the controls (render, single toggle, select/deselect all), the HistoryScreen onUiChange wiring, and the list-level direction filtering. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the Select/Deselect All control in HistoryControls: the per-section Clear/Export on the History/Pinned headers now use a subtle Button (variant subtle, size xs) instead of an Anchor link. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "client → server" / "client ← server" toggles in HistoryControls now color their labels green / violet, matching the MessageDirectionBadge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@claude review |
|
Claude finished @cliffhall's task in 2m 17s —— View job Code Review — PR #1441 (History: Pin & Replay + status fixes)I reviewed the full diff against ✅ What's solid
🔸 Observations / minor
Nits
No correctness blockers found. Items 1 and 2 are the only ones I'd ask you to consciously confirm-or-tweak before merge. |
Review follow-up (#1441): MessageTrackingTransport.send now also tracks the client's own notifications (initialized, progress, roots/list_changed) as origin "client", making send fully symmetric with onmessage. Previously only id-bearing outgoing messages (requests, responses) were tracked, so client notifications never reached History while incoming server notifications did. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks for the thorough review! Addressed in 1. Outgoing client notifications untracked — fixed. Good call; I made 2. Per-section Clear/Export ignore active filters — intentional, left as-is. They operate on the full section by pin membership, matching the existing panel-level Clear/Export (which also ignore the search/method/direction filters). Keeping all three consistent felt less surprising than having section actions respect filters while the panel ones don't — "clear the section = clear the section." Happy to revisit if we later make the panel-level ones filter-aware too. 3. PR description (yellow vs violet) — fixed. Updated section 4 of the description to say violet; the code/comment were already correct. 4. 5. Replay re-runs side effects — by design, acknowledged. Replaying a Nits — agreed, no changes owed. Re-validated: @claude review |
|
Claude finished @cliffhall's task in 1m 0s —— View job Follow-up review —
|
|
Thanks — appreciate the careful re-trace. Confirming your passing note: yes, No further changes. Ready to merge whenever. 🙏 |
History-screen work. Three related changes on one branch.
1. Pin & Replay (#1438)
Both
HistoryEntryactions were rendered but wired totodoNoopinApp.Appowns a session-scopedSet<string>of pinned entry ids, toggled byonTogglePinHistoryand passed down aspinnedHistoryIds.HistoryListPanelalready sorts pinned entries to the top. The set resets with the rest of the per-screen state on disconnect / server-switch.onReplayHistoryre-issues the entry's original request by method:tools/call→callTool,prompts/get→getPrompt,resources/read→readResource. The call flows throughInspectorClient→ tracked transport → message log, so the fresh request+response surface as a new History entry (history-local) without touching the Tools/Prompts/Resources panels. An unsupported method or a removed tool surfaces a toast.2. Notifications no longer stuck "Pending" (#1439)
extractStatusderived the badge purely from whether aresponsewas attached, so a fire-and-forget notification (no id, no response) — and any unmatched standalone response — showed Pending forever. The pending→OK/Error lifecycle only applies todirection === "request"entries; non-request entries now render no request-style badge (the method badge already labels them).3. Server→client requests resolve in history (#1440)
MessageTrackingTransport.sendonly tracked outgoing requests, so the client's response to a server→client request (roots/list, sampling, elicitation) was never recorded — the request sat Pending with no response body.sendis now symmetric withonmessage: it tracks outgoing responses (by id + result/error) too, so the response folds into its request entry and resolves to OK/Error. (Verified the integration "no orphan responses" assertion still holds.)Testing
npm run validate— 2070 unit/integration tests pass; per-file coverage gate green.npm run test:storybook— 333 pass.Closes #1438, closes #1439, closes #1440.
🤖 Generated with Claude Code
4. Direction badge on History & Network (#1437)
A shared dual-state badge at each entry's top-left shows travel direction: client → server (green, inspector-originated) / client ← server (violet, server-originated). History derives it from a new
MessageEntry.originfield set at tracking time (MessageTrackingTransporttags outgoingsendasclient, incomingonmessageasserver). Network fetches are always inspector-originated, so the badge there is constant (outgoing) — the light "tap" noted in the issue.Closes #1437.