Port resource preview UX improvements to PromptsScreen (#1328)#1331
Port resource preview UX improvements to PromptsScreen (#1328)#1331cliffhall wants to merge 8 commits into
Conversation
Brings the prompt-fetching flow up to parity with the resource preview work from #1326: - Cap the argument-form pane at maw=40% so a bare input + button doesn't stretch across wide displays. - Auto-fetch no-argument prompts the moment they're picked from the sidebar (handleSelectPrompt routes them straight to onGetPrompt({})), and hide the form once the user clicks Get Prompt — the result panel takes the same fixed-height column the resource preview uses. - Apply the PreviewCard variant=preview pattern: card sizes to content but caps at viewport, PromptMessagesDisplay pins its header (flex 0 0 auto) and lets the inner ScrollArea (flex 0 1 auto, mih 0) absorb overflow. - Tag getPromptState with the prompt name in App.tsx so the screen can ignore a stale result whose name no longer matches the selection. - MessageBubble now routes each content block through ContentViewer (markdown for text via mimeType="text/markdown", image/audio/resource via existing ContentViewer branches). Non-renderable block types (tool_use, tool_result) are filtered out; the role-label header keeps the bubble visible regardless. - PromptArgumentsForm gains onCompleteArgument + completionsSupported; when both are set, each input becomes Mantine Autocomplete with the same per-arg AbortController + per-arg debounce timer pattern as ResourceTemplatePanel. PromptsScreen + InspectorView + App.tsx wire the callback to inspectorClient.getCompletions with a ref/prompt envelope. Closes #1328. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A top-left CloseButton dismisses the preview panel. The host screen decides what to fall back to: - ResourcesScreen remembers the originating template URI when the user reads from a template form (originatingTemplateUri); closing the preview restores the template form. Plain-resource reads (sidebar selection) just empty the selection and return to the empty state. Picking a different template / resource from the sidebar clears the back-trail. - PromptsScreen flips submittedFor back to undefined when the closed prompt has arguments — the argument form re-renders with the user's values preserved so they can edit and re-submit. No-arg prompts have nothing to fall back to, so the selection is dropped and the empty state appears. The X button is hidden when the host omits onClose, so callers that don't want a dismiss control keep their existing rendering. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The OK-state preview already had its X button (inside the panel component itself). Pending and error states were inline cards in renderReadState / renderPreview with no way to dismiss them, so a user who submitted bad input to a resource template or prompt was stuck staring at the error until they picked a different sidebar item. Adds a top-left CloseButton row to both states on both screens, wired to the same handleClosePreview handler — so the template form or argument form re-appears on close just like it does from the OK state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two fixes to the PromptArgumentsForm autocomplete: - Focusing an argument input now fires completion/complete immediately (handleFocus) — the dropdown is populated as soon as the user clicks in, not only after they start typing. Any in-flight debounce timer for the same arg is cancelled so a stale keystroke request can't overwrite the fresh focus response. - The completion context now includes every declared prompt argument (with "" for ones the user hasn't typed into yet), minus the one being completed. Previously the context only carried args the user had touched, so servers that disambiguate based on co-arguments couldn't see the full picture on the first keystroke. Tests cover both: a focus-only path that fires before any keystroke, and a typing path that asserts the empty sibling is sent through. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the prompt-side change: focusing a template variable input now fires completion/complete immediately so the dropdown populates the moment the user clicks in, rather than waiting for the first keystroke + 300ms debounce. Any pending debounce timer for the same variable is cancelled first so a stale keystroke response can't overwrite the focus response. The sibling-context coverage was already correct here — `variables` is seeded with empty strings for every declared template variable at mount and on template switch, so the context payload always carries the full variable set minus the one being completed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two fixes so the completion dropdowns on prompt-argument and resource-template inputs look like every other dropdown in the app: - App.css: the dark-mode dropdown / option-hover rules used to target .mantine-Select-* only, so the Autocomplete dropdowns shipped with Mantine's default surface color and a different hover background. Re-scoped to .mantine-Combobox-* so every Combobox-built input (Select, Autocomplete, MultiSelect, …) inherits the same styling. - theme/Autocomplete.ts: new theme module setting `radius: "md"` so Autocomplete matches the default Select / TextInput corner radius. Wired through theme/index.ts and theme/theme.ts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous commit re-scoped the dark-mode dropdown rules from `.mantine-Select-*` to `.mantine-Combobox-*` on the assumption that both Select and Autocomplete share a Combobox class on the dropdown root. They don't — Mantine's Combobox factory takes `__staticSelector` from the parent component, so Select emits `mantine-Select-dropdown` and Autocomplete emits `mantine-Autocomplete-dropdown` with no shared `Combobox` class on that element. The `.mantine-Combobox-*` selector matched nothing, so the TaskControls filter (and every other Select) lost its gray surface and reverted to Mantine's default brown-ish dark background. List both selectors so Select dropdowns keep their styling and Autocomplete dropdowns pick it up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follow-up commits since this PR was openedThe initial commit (c61e15f1) covered the original #1328 scope: 40%-width form pane, auto-fetch / auto-hide, sized-to-content preview with viewport cap, markdown in messages, stale-name guard, and live 1. Close (X) buttons on result panels — b1b541b9Added a top-left Mantine
The X button is hidden when the host omits 2. Close button on pending / error states — 6d758749The OK-state preview already had its X button inside the panel component itself, but the pending and error states were inline cards rendered by 3. Fire prompt completions on focus + full sibling context — 5408e164Two fixes to
4. Same focus-fire treatment for resource templates — fd1c7313Mirrored the focus-fire change to 5. Autocomplete dropdown styling — 1561b46e (broken) → 719e7bec (fixed)The completion dropdowns were rendering with Mantine's default dark surface color, which didn't match the gray surface every other dropdown in the app uses. First attempt (broken) scoped the dark-mode dropdown / option-hover CSS to Fix lists both All four pipelines (validate, unit + coverage, integration, storybook) are green at every commit. Resource-side tests were untouched apart from the close-button additions; prompt-side tests cover the new auto-fetch, hide-after-submit, stale-guard, ref/prompt envelope, focus-fire completion, and empty-sibling-context paths. |
|
@claude review |
|
Claude finished @cliffhall's task in 2m 55s —— View job Code ReviewRead the full diff against A few observations below, mostly minor / forward-looking. Nothing blocking — ship as-is if the manual test item at the end of the PR body passes. 1. Prompt text blocks are always rendered as markdown — intentional but irreversible for consumers
Prompts don't carry a 2.
|
- PromptArgumentsForm: add a canSubmit guard that disables Get Prompt until every required argument has a value, matching the resource template form's symmetry. Optional args may stay blank. - Both forms: capture sibling context inside the debounce callback, not at schedule time. Hold the latest argumentValues / variables in a ref + sync via useEffect, and call buildContext() at fire time. Without this, typing in arg A then arg B within the 300ms window would ship A's request with B's pre-keystroke value. - PromptsScreen.handleSelectPrompt: early-return when the user re-clicks the already-selected prompt — sidebar is for navigation, ✕ is for dismiss. Previously a re-click wiped form values and re-fired the auto-fetch for no-arg prompts. - MessageBubble: expand the comment on effectiveMimeForBlock to flag the unconditional markdown promotion as a known asymmetry with the resource side (which only promotes when the server signals it), pending a per-block mimeType in the spec. - New tests: canSubmit disabled / enabled transitions, fire-time context capture across siblings, abort-path verification (a stale in-flight response must not overwrite the fresh one), and the no-op re-click guard on PromptsScreen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for the review! Walking through each item: 1. Prompt text always rendered as markdown — kept current behavior, expanded the comment on 2. 3. Focus fires unbatched — leaving as-is. The per-arg 4. Sibling context captured at keystroke time — fixed for both forms. Both 5. Closing a pending preview leaves the request in flight — leaving as-is per the reviewer's "probably OK to leave" — the 6. Re-click clears 7. Test gap (abort path) — added. New
|
|
@claude review |
|
Claude finished @cliffhall's task in 2m 5s —— View job Follow-up Code ReviewRead the latest diff against Response to prior review items — all verified ✅
New observations this passMinor: asymmetric
|
Summary
Brings the prompts-side flow up to parity with the resource preview work from #1326:
maw=40%on the form pane.handleSelectPromptdecides between auto-fetch (no-arg prompts) vs. form-render (arg-bearing prompts);submittedForflips off the form once the user submits.PreviewCard variant=\"preview\"+PreviewPane mah=SCROLL_MAX_HEIGHT.PromptMessagesDisplaypins its header (flex: 0 0 auto) and the innerScrollArea(flex: 0 1 auto,mih: 0) absorbs overflow.MessageBubbleroutes each content block throughContentViewerwithmimeType=\"text/markdown\"for text blocks; image/audio/resource flow through the existing ContentViewer branches. Non-renderable block types (tool_use, tool_result) are filtered out.App.tsxtagsgetPromptStatewithpromptNameso the screen can ignore a stale result whose name no longer matches the sidebar selection.completion/completeon argument inputs:PromptArgumentsFormacceptsonCompleteArgument+completionsSupported, swapsTextInput→ MantineAutocomplete, mirrors the per-argAbortController+ per-arg timer / 300ms debounce pattern fromResourceTemplatePanel.PromptsScreenre-injects the active prompt name as aref/promptenvelope.App.tsxalready had the callback; just threaded it through.Closes #1328.
Test plan
npm run validate(format, lint, build, unit + coverage gate)npm run test:integration(379 passed)npm run test:storybook(300 passed)completion/complete.🤖 Generated with Claude Code