Refactor ServerCard with active server logic, rename StatusIndicator, and polish UI panels

- Rename StatusIndicator to ServerStatusIndicator across all files
- ServerCard: add activeServer/onSetActiveServer props for coordinated
  connection flow — when a card's toggle is switched on, it sets itself
  as the active server, shows "Connecting" status, and dims all other
  cards (opacity + pointerEvents none + inert for full keyboard blocking)
- ServerListScreen: manage activeServer state internally, pass to cards;
  switch to full-width layout with 3-column grid and scrollable card area
- ServerCard: move "Test Client Features" dropdown above ContentViewer
  with min-height row for consistent card heights
- ToolResultPanel: move Clear button to top-right header row
- ToolDetailPanel: right-align Execute Tool button, size md, not full-width
- ListChangedIndicator: bump Refresh button to size sm
- ToolsActive story: expand to 30 tools with titles
- UnconnectedView stories: all servers disconnected, remove Connecting story

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-04-02 18:00:18 -04:00
commit 8e73bc6ffb
2 changed files with 295 additions and 117 deletions

View file

@ -184,9 +184,174 @@ export const ToolsActive: Story = {
selected: true,
onClick: fn(),
},
{ name: "delete_records", selected: false, onClick: fn() },
{ name: "list_users", selected: false, onClick: fn() },
{ name: "batch_process", selected: false, onClick: fn() },
{
name: "delete_records",
title: "Delete Records",
selected: false,
onClick: fn(),
},
{
name: "list_users",
title: "List Users",
selected: false,
onClick: fn(),
},
{
name: "batch_process",
title: "Batch Process",
selected: false,
onClick: fn(),
},
{
name: "search_files",
title: "Search Files",
selected: false,
onClick: fn(),
},
{
name: "read_file",
title: "Read File",
selected: false,
onClick: fn(),
},
{
name: "write_file",
title: "Write File",
selected: false,
onClick: fn(),
},
{
name: "get_schema",
title: "Get Schema",
selected: false,
onClick: fn(),
},
{
name: "run_query",
title: "Run Query",
selected: false,
onClick: fn(),
},
{
name: "create_migration",
title: "Create Migration",
selected: false,
onClick: fn(),
},
{
name: "validate_config",
title: "Validate Config",
selected: false,
onClick: fn(),
},
{
name: "deploy_service",
title: "Deploy Service",
selected: false,
onClick: fn(),
},
{
name: "rollback_deploy",
title: "Rollback Deploy",
selected: false,
onClick: fn(),
},
{
name: "check_health",
title: "Check Health",
selected: false,
onClick: fn(),
},
{
name: "generate_report",
title: "Generate Report",
selected: false,
onClick: fn(),
},
{
name: "export_csv",
title: "Export CSV",
selected: false,
onClick: fn(),
},
{
name: "import_data",
title: "Import Data",
selected: false,
onClick: fn(),
},
{
name: "send_notification",
title: "Send Notification",
selected: false,
onClick: fn(),
},
{
name: "schedule_task",
title: "Schedule Task",
selected: false,
onClick: fn(),
},
{
name: "cancel_task",
title: "Cancel Task",
selected: false,
onClick: fn(),
},
{
name: "list_connections",
title: "List Connections",
selected: false,
onClick: fn(),
},
{
name: "refresh_cache",
title: "Refresh Cache",
selected: false,
onClick: fn(),
},
{
name: "purge_logs",
title: "Purge Logs",
selected: false,
onClick: fn(),
},
{
name: "encrypt_secret",
title: "Encrypt Secret",
selected: false,
onClick: fn(),
},
{
name: "rotate_keys",
title: "Rotate Keys",
selected: false,
onClick: fn(),
},
{
name: "sync_resources",
title: "Sync Resources",
selected: false,
onClick: fn(),
},
{
name: "compile_template",
title: "Compile Template",
selected: false,
onClick: fn(),
},
{
name: "analyze_performance",
title: "Analyze Performance",
selected: false,
onClick: fn(),
},
{
name: "resize_image",
title: "Resize Image",
selected: false,
onClick: fn(),
},
]}
selectedTool={{
name: "create_record",

View file

@ -59,8 +59,8 @@ export const WithServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-everything",
status: "connected",
canTestClientFeatures: true,
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
{
@ -80,9 +80,7 @@ export const WithServers: Story = {
transport: "http",
connectionMode: "Direct",
command: "https://api.example.com/mcp",
status: "failed",
retryCount: 3,
error: { message: "Connection timeout after 20s" },
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
@ -106,8 +104,8 @@ export const ManyServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-everything",
status: "connected",
canTestClientFeatures: true,
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
{
@ -127,8 +125,8 @@ export const ManyServers: Story = {
transport: "http",
connectionMode: "Direct",
command: "https://api.example.com/mcp",
status: "connected",
canTestClientFeatures: true,
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
{
@ -137,7 +135,7 @@ export const ManyServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-postgres",
status: "connecting",
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
@ -147,8 +145,8 @@ export const ManyServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-github",
status: "connected",
canTestClientFeatures: true,
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
{
@ -157,9 +155,7 @@ export const ManyServers: Story = {
transport: "http",
connectionMode: "Direct",
command: "https://slack-mcp.example.com/mcp",
status: "failed",
retryCount: 5,
error: { message: "Authentication failed" },
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
@ -169,7 +165,7 @@ export const ManyServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-memory",
status: "connected",
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
@ -189,8 +185,8 @@ export const ManyServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-sqlite ./data.db",
status: "connected",
canTestClientFeatures: true,
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
{
@ -199,9 +195,7 @@ export const ManyServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-brave-search",
status: "failed",
retryCount: 2,
error: { message: "API key expired" },
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
@ -221,7 +215,7 @@ export const ManyServers: Story = {
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-sequential-thinking",
status: "connecting",
status: "disconnected",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
@ -232,28 +226,4 @@ export const ManyServers: Story = {
/>
),
},
};
export const Connecting: Story = {
args: {
children: (
<ServerListScreen
servers={[
{
name: "everything-server",
version: "1.0.0",
transport: "stdio",
connectionMode: "Via Proxy",
command: "npx -y @modelcontextprotocol/server-everything",
status: "connecting",
canTestClientFeatures: false,
...makeServerCallbacks(),
},
]}
onAddManually={fn()}
onImportConfig={fn()}
onImportServerJson={fn()}
/>
),
},
};
};