Extensions UI: own Advertised Extensions section + 'Client Advertised Extensions' heading (#1748)
* Settings: move Advertised Extensions to its own accordion section (#1747) The Advertised Extensions control (added in #1739) lived inside the Options accordion panel, wedged between "Fetch Lists One Page at a Time" and "Network Log Size". Promote it to its own top-level "Advertised Extensions" accordion section (after Options), so the distinct concept — which extensions the Inspector advertises to this server in its client capabilities — reads as its own collapsible section. - ServerSettingsForm: add "extensions" to ServerSettingsSection; move the checkbox group into a new Accordion.Item value="extensions". Its description moves up into the panel; no behavior change (still folds into settings.advertisedExtensions via onAdvertisedExtensionChange). - ServerSettingsModal: add "extensions" to allSectionsFor so expand/collapse-all covers it. - Tests: the toggle now lives under the new (collapsed-by-default) section, so the form tests render it expanded and the modal tests open it first. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * Connection Info: rename "Advertised Extensions" heading to "Client Advertised Extensions" Disambiguates the client-side column from the adjacent "Server Extensions" column and from the (separate) Server Settings "Advertised Extensions" section. Label-only change; the value still renders clientCapabilities.extensions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * docs: refresh Connection Info screenshot for the renamed heading Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * docs: refresh #1747 proof screenshots (fresh capture) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 * Settings: add AdvertisedExtensions Storybook story (review) Address the #1748 review's optional note: the new Advertised Extensions accordion section had no story expanding it, so it wasn't documented in the visual catalog (the default story expands only ['options']). Add an AdvertisedExtensions story with expandedSections: ['extensions'] and a per-server override, showing the default-on and toggled-off checkbox states. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e2c75da5ce
commit
c51d6aabd2
9 changed files with 66 additions and 36 deletions
|
|
@ -216,7 +216,9 @@ describe("ConnectionInfoContent", () => {
|
|||
protocolEra="legacy"
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByText("Advertised Extensions")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("Client Advertised Extensions"),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
"io.modelcontextprotocol/tasks, io.modelcontextprotocol/ui",
|
||||
|
|
@ -234,7 +236,9 @@ describe("ConnectionInfoContent", () => {
|
|||
/>,
|
||||
);
|
||||
expect(screen.getByText("Server Extensions")).toBeInTheDocument();
|
||||
expect(screen.getByText("Advertised Extensions")).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("Client Advertised Extensions"),
|
||||
).toBeInTheDocument();
|
||||
// Exactly two em dashes: the two extension sections (the server version is
|
||||
// present in the fixture, so it does not em-dash).
|
||||
expect(screen.getAllByText("—")).toHaveLength(2);
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ export function ConnectionInfoContent({
|
|||
<ValueText>{formatExtensions(capabilities.extensions)}</ValueText>
|
||||
</Stack>
|
||||
<Stack gap="xs">
|
||||
<SectionHeading>Advertised Extensions</SectionHeading>
|
||||
<SectionHeading>Client Advertised Extensions</SectionHeading>
|
||||
<ValueText>
|
||||
{formatExtensions(clientCapabilities.extensions)}
|
||||
</ValueText>
|
||||
|
|
|
|||
|
|
@ -233,6 +233,19 @@ export const WithHeaders: Story = {
|
|||
},
|
||||
};
|
||||
|
||||
export const AdvertisedExtensions: Story = {
|
||||
args: {
|
||||
// Expand the standalone Advertised Extensions section so its checkboxes are
|
||||
// documented visually. A per-server override disables one extension, showing
|
||||
// both the default-on and toggled-off states side by side.
|
||||
expandedSections: ["extensions"],
|
||||
settings: {
|
||||
...defaultSettings,
|
||||
advertisedExtensions: { "io.modelcontextprotocol/tasks": false },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithOAuth: Story = {
|
||||
args: {
|
||||
settings: {
|
||||
|
|
|
|||
|
|
@ -458,9 +458,13 @@ describe("ServerSettingsForm", () => {
|
|||
<ServerSettingsForm
|
||||
{...baseHandlers}
|
||||
settings={emptySettings}
|
||||
expandedSections={["options"]}
|
||||
expandedSections={["extensions"]}
|
||||
/>,
|
||||
);
|
||||
// Advertised Extensions is now its own accordion section (#1747).
|
||||
expect(
|
||||
screen.getByRole("button", { name: "Advertised Extensions" }),
|
||||
).toBeInTheDocument();
|
||||
const tasks = screen.getByRole("checkbox", {
|
||||
name: /Tasks \(io\.modelcontextprotocol\/tasks\)/,
|
||||
});
|
||||
|
|
@ -476,7 +480,7 @@ describe("ServerSettingsForm", () => {
|
|||
...emptySettings,
|
||||
advertisedExtensions: { "io.modelcontextprotocol/tasks": false },
|
||||
}}
|
||||
expandedSections={["options"]}
|
||||
expandedSections={["extensions"]}
|
||||
/>,
|
||||
);
|
||||
expect(
|
||||
|
|
@ -494,7 +498,7 @@ describe("ServerSettingsForm", () => {
|
|||
{...baseHandlers}
|
||||
onAdvertisedExtensionChange={onAdvertisedExtensionChange}
|
||||
settings={emptySettings}
|
||||
expandedSections={["options"]}
|
||||
expandedSections={["extensions"]}
|
||||
/>,
|
||||
);
|
||||
// Default is checked; clicking flips it to unadvertised.
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ function isExtensionAdvertised(
|
|||
|
||||
export type ServerSettingsSection =
|
||||
| "options"
|
||||
| "extensions"
|
||||
| "environment"
|
||||
| "headers"
|
||||
| "metadata"
|
||||
|
|
@ -401,34 +402,6 @@ export function ServerSettingsForm({
|
|||
checked={settings.paginatedLists ?? false}
|
||||
onChange={(e) => onPaginatedListsChange(e.currentTarget.checked)}
|
||||
/>
|
||||
<Stack gap="xs">
|
||||
<Text size="sm" fw={500}>
|
||||
Advertised Extensions
|
||||
</Text>
|
||||
<Text size="xs" c="var(--inspector-text-secondary)">
|
||||
Which extensions the Inspector declares to this server in its
|
||||
client capabilities. A server may register different tools
|
||||
depending on what the client advertises — toggle these to debug
|
||||
that. Takes effect on the next connect.
|
||||
</Text>
|
||||
{ADVERTISABLE_EXTENSIONS.map((ext) => (
|
||||
<Checkbox
|
||||
key={ext.key}
|
||||
label={ext.label}
|
||||
checked={isExtensionAdvertised(
|
||||
settings,
|
||||
ext.key,
|
||||
ext.defaultAdvertised,
|
||||
)}
|
||||
onChange={(e) =>
|
||||
onAdvertisedExtensionChange(
|
||||
ext.key,
|
||||
e.currentTarget.checked,
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
<NumberInput
|
||||
label="Network Log Size"
|
||||
description="Maximum number of HTTP requests kept in the Network log for this server. Older entries rotate out past this limit; a response body that arrives after its entry rotated out is dropped. Use 0 for unlimited (not recommended). Applies immediately to the active connection."
|
||||
|
|
@ -456,6 +429,34 @@ export function ServerSettingsForm({
|
|||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
|
||||
<Accordion.Item value="extensions">
|
||||
<Accordion.Control>Advertised Extensions</Accordion.Control>
|
||||
<Accordion.Panel>
|
||||
<Stack gap="xs">
|
||||
<Text size="xs" c="var(--inspector-text-secondary)">
|
||||
Which extensions the Inspector declares to this server in its
|
||||
client capabilities. A server may register different tools
|
||||
depending on what the client advertises — toggle these to debug
|
||||
that. Takes effect on the next connect.
|
||||
</Text>
|
||||
{ADVERTISABLE_EXTENSIONS.map((ext) => (
|
||||
<Checkbox
|
||||
key={ext.key}
|
||||
label={ext.label}
|
||||
checked={isExtensionAdvertised(
|
||||
settings,
|
||||
ext.key,
|
||||
ext.defaultAdvertised,
|
||||
)}
|
||||
onChange={(e) =>
|
||||
onAdvertisedExtensionChange(ext.key, e.currentTarget.checked)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
|
||||
{isStdio ? (
|
||||
<Accordion.Item value="environment">
|
||||
<Accordion.Control>Environment Variables</Accordion.Control>
|
||||
|
|
|
|||
|
|
@ -175,8 +175,11 @@ describe("ServerSettingsModal", () => {
|
|||
onSettingsChange={onSettingsChange}
|
||||
/>,
|
||||
);
|
||||
// The Options section is expanded by default; Tasks is checked (registry
|
||||
// default), so clicking it toggles the override off.
|
||||
// Advertised Extensions is its own accordion section (#1747), collapsed by
|
||||
// default — open it, then toggle Tasks (checked by the registry default) off.
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Advertised Extensions" }),
|
||||
);
|
||||
await user.click(
|
||||
screen.getByRole("checkbox", {
|
||||
name: /Tasks \(io\.modelcontextprotocol\/tasks\)/,
|
||||
|
|
@ -207,6 +210,10 @@ describe("ServerSettingsModal", () => {
|
|||
onSettingsChange={onSettingsChange}
|
||||
/>,
|
||||
);
|
||||
// Open the Advertised Extensions section (#1747), then re-check Tasks.
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: "Advertised Extensions" }),
|
||||
);
|
||||
await user.click(
|
||||
screen.getByRole("checkbox", {
|
||||
name: /Tasks \(io\.modelcontextprotocol\/tasks\)/,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ function allSectionsFor(
|
|||
): ServerSettingsSection[] {
|
||||
return [
|
||||
"options",
|
||||
"extensions",
|
||||
...(isStdio ? (["environment"] as const) : []),
|
||||
"headers",
|
||||
"metadata",
|
||||
|
|
|
|||
BIN
pr-screenshots/adv-ext-own-section-conninfo.png
Normal file
BIN
pr-screenshots/adv-ext-own-section-conninfo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
BIN
pr-screenshots/adv-ext-own-section.png
Normal file
BIN
pr-screenshots/adv-ext-own-section.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
Loading…
Reference in a new issue