Phase 2: Refactor Prompts cluster to MCP SDK types
Replace ad hoc local types with MCP SDK schema types across the Prompts group components and PromptsScreen, per the v2 UX interfaces plan. - PromptListItem: accept `prompt: Prompt` instead of flat `name`/`description`; render `title ?? name` as primary label - PromptControls: accept `Prompt[]` + `selectedName` instead of `PromptItem[]`; no-op on clicking already-selected prompt; search includes title field - PromptArgumentsForm: accept `prompt: Prompt` instead of flat props; read `prompt.arguments` directly; display `title ?? name` as heading - PromptMessagesDisplay: narrow type from `(PromptMessage | SamplingMessage)[]` to `PromptMessage[]` per spec - PromptsScreen: accept `Prompt[]` + `selectedPromptName` + `GetPromptState`; derive selected prompt via `prompts.find()`; own `argumentValues` state locally; reset arguments on tool switch - Delete local `PromptItem`, `SelectedPrompt`, `PromptArgument` types - Update all stories with real SDK `Prompt` fixtures - Update ConnectedView PromptsActive story Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
12c41cbed7
commit
de40b3720e
2 changed files with 230 additions and 226 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import type { Prompt } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { fn } from "storybook/test";
|
||||
import { PromptsScreen } from "./PromptsScreen";
|
||||
import type { PromptItem, SelectedPrompt } from "./PromptsScreen";
|
||||
import type { GetPromptState } from "./PromptsScreen";
|
||||
|
||||
const meta: Meta<typeof PromptsScreen> = {
|
||||
title: "Screens/PromptsScreen",
|
||||
|
|
@ -10,8 +11,8 @@ const meta: Meta<typeof PromptsScreen> = {
|
|||
args: {
|
||||
onRefreshList: fn(),
|
||||
onSelectPrompt: fn(),
|
||||
onArgumentChange: fn(),
|
||||
onGetPrompt: fn(),
|
||||
onCopyMessages: fn(),
|
||||
listChanged: false,
|
||||
},
|
||||
};
|
||||
|
|
@ -19,42 +20,54 @@ const meta: Meta<typeof PromptsScreen> = {
|
|||
export default meta;
|
||||
type Story = StoryObj<typeof PromptsScreen>;
|
||||
|
||||
const samplePrompts: PromptItem[] = [
|
||||
const samplePrompts: Prompt[] = [
|
||||
{
|
||||
name: "summarize",
|
||||
description: "Summarize the given text into key points",
|
||||
selected: false,
|
||||
},
|
||||
{
|
||||
name: "translate",
|
||||
description: "Translate text from one language to another",
|
||||
selected: false,
|
||||
arguments: [
|
||||
{ name: "text", required: true, description: "The text to translate" },
|
||||
{
|
||||
name: "targetLanguage",
|
||||
required: true,
|
||||
description: "Target language code",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "code-review",
|
||||
description: "Review code for issues",
|
||||
selected: false,
|
||||
},
|
||||
{
|
||||
name: "analyze",
|
||||
description: "Analyze sentiment and tone of the text",
|
||||
selected: false,
|
||||
},
|
||||
{ name: "refactor", selected: false },
|
||||
{ name: "refactor" },
|
||||
];
|
||||
|
||||
const selectedTranslate: SelectedPrompt = {
|
||||
name: "translate",
|
||||
description: "Translate text from one language to another",
|
||||
arguments: [
|
||||
{ name: "text", required: true, description: "The text to translate" },
|
||||
{
|
||||
name: "targetLanguage",
|
||||
required: true,
|
||||
description: "Target language code",
|
||||
},
|
||||
],
|
||||
argumentValues: {},
|
||||
const translateResult: GetPromptState = {
|
||||
status: "ok",
|
||||
result: {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: {
|
||||
type: "text",
|
||||
text: 'Translate the following text to Spanish: "Hello, how are you?"',
|
||||
},
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: {
|
||||
type: "text",
|
||||
text: "Hola, como estas?",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const NoSelection: Story = {
|
||||
|
|
@ -65,44 +78,16 @@ export const NoSelection: Story = {
|
|||
|
||||
export const PromptSelected: Story = {
|
||||
args: {
|
||||
prompts: samplePrompts.map((p) =>
|
||||
p.name === "translate" ? { ...p, selected: true } : p,
|
||||
),
|
||||
selectedPrompt: selectedTranslate,
|
||||
prompts: samplePrompts,
|
||||
selectedPromptName: "translate",
|
||||
},
|
||||
};
|
||||
|
||||
export const WithResult: Story = {
|
||||
args: {
|
||||
prompts: samplePrompts.map((p) =>
|
||||
p.name === "translate" ? { ...p, selected: true } : p,
|
||||
),
|
||||
selectedPrompt: {
|
||||
...selectedTranslate,
|
||||
argumentValues: {
|
||||
text: "Hello, how are you?",
|
||||
targetLanguage: "es",
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
onCopyAll: fn(),
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: {
|
||||
type: "text",
|
||||
text: 'Translate the following text to Spanish: "Hello, how are you?"',
|
||||
},
|
||||
},
|
||||
{
|
||||
role: "assistant",
|
||||
content: {
|
||||
type: "text",
|
||||
text: "Hola, como estas?",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
prompts: samplePrompts,
|
||||
selectedPromptName: "translate",
|
||||
getPromptState: translateResult,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,32 +1,28 @@
|
|||
import { useState } from "react";
|
||||
import { Card, Flex, Group, ScrollArea, Stack, Text } from "@mantine/core";
|
||||
import type {
|
||||
GetPromptResult,
|
||||
Prompt,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import { PromptControls } from "../../groups/PromptControls/PromptControls";
|
||||
import { PromptArgumentsForm } from "../../groups/PromptArgumentsForm/PromptArgumentsForm";
|
||||
import { PromptMessagesDisplay } from "../../groups/PromptMessagesDisplay/PromptMessagesDisplay";
|
||||
import type { PromptArgument } from "../../groups/PromptArgumentsForm/PromptArgumentsForm";
|
||||
import type { PromptMessagesDisplayProps } from "../../groups/PromptMessagesDisplay/PromptMessagesDisplay";
|
||||
|
||||
export interface PromptItem {
|
||||
name: string;
|
||||
description?: string;
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
export interface SelectedPrompt {
|
||||
name: string;
|
||||
description?: string;
|
||||
arguments: PromptArgument[];
|
||||
argumentValues: Record<string, string>;
|
||||
export interface GetPromptState {
|
||||
status: "idle" | "pending" | "ok" | "error";
|
||||
result?: GetPromptResult;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface PromptsScreenProps {
|
||||
prompts: PromptItem[];
|
||||
selectedPrompt?: SelectedPrompt;
|
||||
messages?: PromptMessagesDisplayProps;
|
||||
prompts: Prompt[];
|
||||
selectedPromptName?: string;
|
||||
getPromptState?: GetPromptState;
|
||||
listChanged: boolean;
|
||||
onRefreshList: () => void;
|
||||
onSelectPrompt: (name: string) => void;
|
||||
onArgumentChange: (name: string, value: string) => void;
|
||||
onGetPrompt: () => void;
|
||||
onGetPrompt: (name: string, args: Record<string, string>) => void;
|
||||
onCopyMessages?: () => void;
|
||||
}
|
||||
|
||||
const ScreenLayout = Flex.withProps({
|
||||
|
|
@ -60,23 +56,34 @@ const EmptyState = Text.withProps({
|
|||
|
||||
export function PromptsScreen({
|
||||
prompts,
|
||||
selectedPrompt,
|
||||
messages,
|
||||
selectedPromptName,
|
||||
getPromptState,
|
||||
listChanged,
|
||||
onRefreshList,
|
||||
onSelectPrompt,
|
||||
onArgumentChange,
|
||||
onGetPrompt,
|
||||
onCopyMessages,
|
||||
}: PromptsScreenProps) {
|
||||
const [argumentValues, setArgumentValues] = useState<Record<string, string>>(
|
||||
{},
|
||||
);
|
||||
const selectedPrompt = selectedPromptName
|
||||
? prompts.find((p) => p.name === selectedPromptName)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<ScreenLayout>
|
||||
<Sidebar>
|
||||
<SidebarCard>
|
||||
<PromptControls
|
||||
prompts={prompts}
|
||||
selectedName={selectedPromptName}
|
||||
listChanged={listChanged}
|
||||
onRefreshList={onRefreshList}
|
||||
onSelectPrompt={onSelectPrompt}
|
||||
onSelectPrompt={(name) => {
|
||||
setArgumentValues({});
|
||||
onSelectPrompt(name);
|
||||
}}
|
||||
/>
|
||||
</SidebarCard>
|
||||
</Sidebar>
|
||||
|
|
@ -90,17 +97,22 @@ export function PromptsScreen({
|
|||
<>
|
||||
<DetailCard>
|
||||
<PromptArgumentsForm
|
||||
name={selectedPrompt.name}
|
||||
description={selectedPrompt.description}
|
||||
arguments={selectedPrompt.arguments}
|
||||
argumentValues={selectedPrompt.argumentValues}
|
||||
onArgumentChange={onArgumentChange}
|
||||
onGetPrompt={onGetPrompt}
|
||||
prompt={selectedPrompt}
|
||||
argumentValues={argumentValues}
|
||||
onArgumentChange={(name, value) =>
|
||||
setArgumentValues((prev) => ({ ...prev, [name]: value }))
|
||||
}
|
||||
onGetPrompt={() =>
|
||||
onGetPrompt(selectedPrompt.name, argumentValues)
|
||||
}
|
||||
/>
|
||||
</DetailCard>
|
||||
{messages && (
|
||||
{getPromptState?.result && (
|
||||
<DetailCard>
|
||||
<PromptMessagesDisplay {...messages} />
|
||||
<PromptMessagesDisplay
|
||||
messages={getPromptState.result.messages}
|
||||
onCopyAll={onCopyMessages}
|
||||
/>
|
||||
</DetailCard>
|
||||
)}
|
||||
</>
|
||||
|
|
|
|||
Loading…
Reference in a new issue