Fix ServerSettingsForm stories to use useArgs for action logging
Use Storybook's useArgs hook from storybook/preview-api to update args from within the render function. This wires fn() callbacks to the Actions panel AND updates the UI state through Storybook's args system. All form interactions (add/remove/edit headers/metadata, accordion open/close, connection mode, timeouts, OAuth) now both update the UI and log to the Actions panel. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a3be456f56
commit
e04befa4dd
1 changed files with 140 additions and 104 deletions
|
|
@ -1,9 +1,10 @@
|
||||||
import { useState } from "react";
|
|
||||||
import type { InspectorServerSettings } from "@inspector/core/mcp/types.js";
|
import type { InspectorServerSettings } from "@inspector/core/mcp/types.js";
|
||||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||||
|
import { fn } from "storybook/test";
|
||||||
|
import { useArgs } from "storybook/preview-api";
|
||||||
import {
|
import {
|
||||||
ServerSettingsForm,
|
ServerSettingsForm,
|
||||||
type ServerSettingsSection,
|
type ServerSettingsFormProps,
|
||||||
} from "./ServerSettingsForm";
|
} from "./ServerSettingsForm";
|
||||||
|
|
||||||
const defaultSettings: InspectorServerSettings = {
|
const defaultSettings: InspectorServerSettings = {
|
||||||
|
|
@ -14,74 +15,99 @@ const defaultSettings: InspectorServerSettings = {
|
||||||
requestTimeout: 60000,
|
requestTimeout: 60000,
|
||||||
};
|
};
|
||||||
|
|
||||||
function InteractiveForm({
|
function InteractiveRender(args: ServerSettingsFormProps) {
|
||||||
startSettings,
|
const [, updateArgs] = useArgs<ServerSettingsFormProps>();
|
||||||
initialSections = ["connectionMode"],
|
|
||||||
}: {
|
|
||||||
startSettings: InspectorServerSettings;
|
|
||||||
initialSections?: ServerSettingsSection[];
|
|
||||||
}) {
|
|
||||||
const [expandedSections, setExpandedSections] =
|
|
||||||
useState<ServerSettingsSection[]>(initialSections);
|
|
||||||
const [settings, setSettings] =
|
|
||||||
useState<InspectorServerSettings>(startSettings);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ServerSettingsForm
|
<ServerSettingsForm
|
||||||
settings={settings}
|
{...args}
|
||||||
expandedSections={expandedSections}
|
onExpandedSectionsChange={(sections) => {
|
||||||
onExpandedSectionsChange={setExpandedSections}
|
args.onExpandedSectionsChange(sections);
|
||||||
onConnectionModeChange={(mode) =>
|
updateArgs({ expandedSections: sections });
|
||||||
setSettings((s) => ({ ...s, connectionMode: mode }))
|
}}
|
||||||
}
|
onConnectionModeChange={(mode) => {
|
||||||
onAddHeader={() =>
|
args.onConnectionModeChange(mode);
|
||||||
setSettings((s) => ({
|
updateArgs({
|
||||||
...s,
|
settings: { ...args.settings, connectionMode: mode },
|
||||||
headers: [...s.headers, { key: "", value: "" }],
|
});
|
||||||
}))
|
}}
|
||||||
}
|
onAddHeader={() => {
|
||||||
onRemoveHeader={(index) =>
|
args.onAddHeader();
|
||||||
setSettings((s) => ({
|
updateArgs({
|
||||||
...s,
|
settings: {
|
||||||
headers: s.headers.filter((_, i) => i !== index),
|
...args.settings,
|
||||||
}))
|
headers: [...args.settings.headers, { key: "", value: "" }],
|
||||||
}
|
},
|
||||||
onHeaderChange={(index, key, value) =>
|
});
|
||||||
setSettings((s) => ({
|
}}
|
||||||
...s,
|
onRemoveHeader={(index) => {
|
||||||
headers: s.headers.map((h, i) => (i === index ? { key, value } : h)),
|
args.onRemoveHeader(index);
|
||||||
}))
|
updateArgs({
|
||||||
}
|
settings: {
|
||||||
onAddMetadata={() =>
|
...args.settings,
|
||||||
setSettings((s) => ({
|
headers: args.settings.headers.filter((_, i) => i !== index),
|
||||||
...s,
|
},
|
||||||
metadata: [...s.metadata, { key: "", value: "" }],
|
});
|
||||||
}))
|
}}
|
||||||
}
|
onHeaderChange={(index, key, value) => {
|
||||||
onRemoveMetadata={(index) =>
|
args.onHeaderChange(index, key, value);
|
||||||
setSettings((s) => ({
|
updateArgs({
|
||||||
...s,
|
settings: {
|
||||||
metadata: s.metadata.filter((_, i) => i !== index),
|
...args.settings,
|
||||||
}))
|
headers: args.settings.headers.map((h, i) =>
|
||||||
}
|
i === index ? { key, value } : h,
|
||||||
onMetadataChange={(index, key, value) =>
|
),
|
||||||
setSettings((s) => ({
|
},
|
||||||
...s,
|
});
|
||||||
metadata: s.metadata.map((m, i) =>
|
}}
|
||||||
i === index ? { key, value } : m,
|
onAddMetadata={() => {
|
||||||
),
|
args.onAddMetadata();
|
||||||
}))
|
updateArgs({
|
||||||
}
|
settings: {
|
||||||
onTimeoutChange={(field, value) =>
|
...args.settings,
|
||||||
setSettings((s) => ({ ...s, [field]: value }))
|
metadata: [...args.settings.metadata, { key: "", value: "" }],
|
||||||
}
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onRemoveMetadata={(index) => {
|
||||||
|
args.onRemoveMetadata(index);
|
||||||
|
updateArgs({
|
||||||
|
settings: {
|
||||||
|
...args.settings,
|
||||||
|
metadata: args.settings.metadata.filter((_, i) => i !== index),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onMetadataChange={(index, key, value) => {
|
||||||
|
args.onMetadataChange(index, key, value);
|
||||||
|
updateArgs({
|
||||||
|
settings: {
|
||||||
|
...args.settings,
|
||||||
|
metadata: args.settings.metadata.map((m, i) =>
|
||||||
|
i === index ? { key, value } : m,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
onTimeoutChange={(field, value) => {
|
||||||
|
args.onTimeoutChange(field, value);
|
||||||
|
updateArgs({
|
||||||
|
settings: { ...args.settings, [field]: value },
|
||||||
|
});
|
||||||
|
}}
|
||||||
onOAuthChange={(field, value) => {
|
onOAuthChange={(field, value) => {
|
||||||
|
args.onOAuthChange(field, value);
|
||||||
const fieldMap: Record<string, string> = {
|
const fieldMap: Record<string, string> = {
|
||||||
clientId: "oauthClientId",
|
clientId: "oauthClientId",
|
||||||
clientSecret: "oauthClientSecret",
|
clientSecret: "oauthClientSecret",
|
||||||
scopes: "oauthScopes",
|
scopes: "oauthScopes",
|
||||||
};
|
};
|
||||||
setSettings((s) => ({ ...s, [fieldMap[field] ?? field]: value }));
|
updateArgs({
|
||||||
|
settings: {
|
||||||
|
...args.settings,
|
||||||
|
[fieldMap[field] ?? field]: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -90,62 +116,72 @@ function InteractiveForm({
|
||||||
const meta: Meta<typeof ServerSettingsForm> = {
|
const meta: Meta<typeof ServerSettingsForm> = {
|
||||||
title: "Groups/ServerSettingsForm",
|
title: "Groups/ServerSettingsForm",
|
||||||
component: ServerSettingsForm,
|
component: ServerSettingsForm,
|
||||||
|
render: InteractiveRender,
|
||||||
|
args: {
|
||||||
|
expandedSections: ["connectionMode"],
|
||||||
|
onExpandedSectionsChange: fn(),
|
||||||
|
onConnectionModeChange: fn(),
|
||||||
|
onAddHeader: fn(),
|
||||||
|
onRemoveHeader: fn(),
|
||||||
|
onHeaderChange: fn(),
|
||||||
|
onAddMetadata: fn(),
|
||||||
|
onRemoveMetadata: fn(),
|
||||||
|
onMetadataChange: fn(),
|
||||||
|
onTimeoutChange: fn(),
|
||||||
|
onOAuthChange: fn(),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
type Story = StoryObj<typeof ServerSettingsForm>;
|
type Story = StoryObj<typeof ServerSettingsForm>;
|
||||||
|
|
||||||
export const DefaultSettings: Story = {
|
export const DefaultSettings: Story = {
|
||||||
render: () => <InteractiveForm startSettings={defaultSettings} />,
|
args: {
|
||||||
|
settings: defaultSettings,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WithHeaders: Story = {
|
export const WithHeaders: Story = {
|
||||||
render: () => (
|
args: {
|
||||||
<InteractiveForm
|
settings: {
|
||||||
startSettings={{
|
...defaultSettings,
|
||||||
...defaultSettings,
|
headers: [
|
||||||
headers: [
|
{ key: "Authorization", value: "Bearer token-abc-123" },
|
||||||
{ key: "Authorization", value: "Bearer token-abc-123" },
|
{ key: "X-Custom-Header", value: "custom-value" },
|
||||||
{ key: "X-Custom-Header", value: "custom-value" },
|
],
|
||||||
],
|
},
|
||||||
}}
|
},
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WithOAuth: Story = {
|
export const WithOAuth: Story = {
|
||||||
render: () => (
|
args: {
|
||||||
<InteractiveForm
|
settings: {
|
||||||
startSettings={{
|
...defaultSettings,
|
||||||
...defaultSettings,
|
connectionMode: "direct",
|
||||||
connectionMode: "direct",
|
oauthClientId: "my-client-id",
|
||||||
oauthClientId: "my-client-id",
|
oauthClientSecret: "super-secret-value",
|
||||||
oauthClientSecret: "super-secret-value",
|
oauthScopes: "read write admin",
|
||||||
oauthScopes: "read write admin",
|
},
|
||||||
}}
|
},
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AllConfigured: Story = {
|
export const AllConfigured: Story = {
|
||||||
render: () => (
|
args: {
|
||||||
<InteractiveForm
|
settings: {
|
||||||
startSettings={{
|
connectionMode: "proxy",
|
||||||
connectionMode: "proxy",
|
headers: [
|
||||||
headers: [
|
{ key: "Authorization", value: "Bearer token-abc-123" },
|
||||||
{ key: "Authorization", value: "Bearer token-abc-123" },
|
{ key: "X-Request-Id", value: "req-456" },
|
||||||
{ key: "X-Request-Id", value: "req-456" },
|
],
|
||||||
],
|
metadata: [
|
||||||
metadata: [
|
{ key: "userId", value: "user-789" },
|
||||||
{ key: "userId", value: "user-789" },
|
{ key: "sessionId", value: "session-012" },
|
||||||
{ key: "sessionId", value: "session-012" },
|
],
|
||||||
],
|
connectionTimeout: 15000,
|
||||||
connectionTimeout: 15000,
|
requestTimeout: 45000,
|
||||||
requestTimeout: 45000,
|
oauthClientId: "my-client-id",
|
||||||
oauthClientId: "my-client-id",
|
oauthClientSecret: "super-secret-value",
|
||||||
oauthClientSecret: "super-secret-value",
|
oauthScopes: "read write",
|
||||||
oauthScopes: "read write",
|
},
|
||||||
}}
|
},
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue