Skip to content

Commit 93b1ec4

Browse files
committed
Move connection settings UI into left sidebar
1 parent ab9c130 commit 93b1ec4

File tree

2 files changed

+202
-148
lines changed

2 files changed

+202
-148
lines changed

client/src/App.tsx

Lines changed: 14 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,16 @@ if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
2828
document.documentElement.classList.add("dark");
2929
}
3030

31-
import { Button } from "@/components/ui/button";
32-
import { Input } from "@/components/ui/input";
33-
import {
34-
Select,
35-
SelectContent,
36-
SelectItem,
37-
SelectTrigger,
38-
SelectValue,
39-
} from "@/components/ui/select";
4031
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
4132
import {
4233
Bell,
4334
Files,
4435
Hammer,
4536
Hash,
4637
MessageSquare,
47-
Play,
4838
Send,
4939
Terminal,
5040
FolderTree,
51-
ChevronDown,
52-
ChevronRight,
5341
} from "lucide-react";
5442

5543
import { ZodType } from "zod";
@@ -95,7 +83,6 @@ const App = () => {
9583
const [notifications, setNotifications] = useState<ServerNotification[]>([]);
9684
const [roots, setRoots] = useState<Root[]>([]);
9785
const [env, setEnv] = useState<Record<string, string>>({});
98-
const [showEnvVars, setShowEnvVars] = useState(false);
9986

10087
const [pendingSampleRequests, setPendingSampleRequests] = useState<
10188
Array<
@@ -353,114 +340,24 @@ const App = () => {
353340

354341
return (
355342
<div className="flex h-screen bg-background">
356-
<Sidebar connectionStatus={connectionStatus} />
343+
<Sidebar
344+
connectionStatus={connectionStatus}
345+
transportType={transportType}
346+
setTransportType={setTransportType}
347+
command={command}
348+
setCommand={setCommand}
349+
args={args}
350+
setArgs={setArgs}
351+
url={url}
352+
setUrl={setUrl}
353+
env={env}
354+
setEnv={setEnv}
355+
onConnect={connectMcpServer}
356+
/>
357357
<div className="flex-1 flex flex-col overflow-hidden">
358358
<h1 className="text-2xl font-bold p-4">MCP Inspector</h1>
359359
<div className="flex-1 overflow-auto flex">
360360
<div className="flex-1">
361-
<div className="p-4 bg-card shadow-md m-4 rounded-md">
362-
<h2 className="text-lg font-semibold mb-2">Connect MCP Server</h2>
363-
<div className="flex space-x-2 mb-2">
364-
<Select
365-
value={transportType}
366-
onValueChange={(value: "stdio" | "sse") =>
367-
setTransportType(value)
368-
}
369-
>
370-
<SelectTrigger className="w-[180px]">
371-
<SelectValue placeholder="Select transport type" />
372-
</SelectTrigger>
373-
<SelectContent>
374-
<SelectItem value="stdio">STDIO</SelectItem>
375-
<SelectItem value="sse">SSE</SelectItem>
376-
</SelectContent>
377-
</Select>
378-
{transportType === "stdio" ? (
379-
<>
380-
<Input
381-
placeholder="Command"
382-
value={command}
383-
onChange={(e) => setCommand(e.target.value)}
384-
/>
385-
<Input
386-
placeholder="Arguments (space-separated)"
387-
value={args}
388-
onChange={(e) => setArgs(e.target.value)}
389-
/>
390-
</>
391-
) : (
392-
<Input
393-
placeholder="URL"
394-
value={url}
395-
onChange={(e) => setUrl(e.target.value)}
396-
/>
397-
)}
398-
<Button onClick={connectMcpServer}>
399-
<Play className="w-4 h-4 mr-2" />
400-
Connect
401-
</Button>
402-
</div>
403-
{transportType === "stdio" && (
404-
<div className="mt-4">
405-
<Button
406-
variant="outline"
407-
onClick={() => setShowEnvVars(!showEnvVars)}
408-
className="flex items-center"
409-
>
410-
{showEnvVars ? (
411-
<ChevronDown className="w-4 h-4 mr-2" />
412-
) : (
413-
<ChevronRight className="w-4 h-4 mr-2" />
414-
)}
415-
Environment Variables
416-
</Button>
417-
{showEnvVars && (
418-
<div className="mt-2">
419-
{Object.entries(env).map(([key, value]) => (
420-
<div key={key} className="flex space-x-2 mb-2">
421-
<Input
422-
placeholder="Key"
423-
value={key}
424-
onChange={(e) =>
425-
setEnv((prev) => ({
426-
...prev,
427-
[e.target.value]: value,
428-
}))
429-
}
430-
/>
431-
<Input
432-
placeholder="Value"
433-
value={value}
434-
onChange={(e) =>
435-
setEnv((prev) => ({
436-
...prev,
437-
[key]: e.target.value,
438-
}))
439-
}
440-
/>
441-
<Button
442-
onClick={() =>
443-
setEnv((prev) => {
444-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
445-
const { [key]: _, ...rest } = prev;
446-
return rest;
447-
})
448-
}
449-
>
450-
Remove
451-
</Button>
452-
</div>
453-
))}
454-
<Button
455-
onClick={() => setEnv((prev) => ({ ...prev, "": "" }))}
456-
>
457-
Add Environment Variable
458-
</Button>
459-
</div>
460-
)}
461-
</div>
462-
)}
463-
</div>
464361
{mcpClient ? (
465362
<Tabs defaultValue="resources" className="w-full p-4">
466363
<TabsList className="mb-4 p-0">

client/src/components/Sidebar.tsx

Lines changed: 188 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,196 @@
1-
import { Menu, Settings } from "lucide-react";
1+
import { useState } from "react";
2+
3+
import { Play, ChevronDown, ChevronRight, Settings } from "lucide-react";
24
import { Button } from "@/components/ui/button";
5+
import { Input } from "@/components/ui/input";
6+
import {
7+
Select,
8+
SelectContent,
9+
SelectItem,
10+
SelectTrigger,
11+
SelectValue,
12+
} from "@/components/ui/select";
313

4-
const Sidebar = ({ connectionStatus }: { connectionStatus: string }) => (
5-
<div className="w-64 bg-card border-r border-border">
6-
<div className="flex items-center p-4 border-b border-gray-200">
7-
<Menu className="w-6 h-6 text-gray-500" />
8-
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
9-
</div>
14+
interface SidebarProps {
15+
connectionStatus: "disconnected" | "connected" | "error";
16+
transportType: "stdio" | "sse";
17+
setTransportType: (type: "stdio" | "sse") => void;
18+
command: string;
19+
setCommand: (command: string) => void;
20+
args: string;
21+
setArgs: (args: string) => void;
22+
url: string;
23+
setUrl: (url: string) => void;
24+
env: Record<string, string>;
25+
setEnv: (env: Record<string, string>) => void;
26+
onConnect: () => void;
27+
}
28+
29+
const Sidebar = ({
30+
connectionStatus,
31+
transportType,
32+
setTransportType,
33+
command,
34+
setCommand,
35+
args,
36+
setArgs,
37+
url,
38+
setUrl,
39+
env,
40+
setEnv,
41+
onConnect,
42+
}: SidebarProps) => {
43+
const [showEnvVars, setShowEnvVars] = useState(false);
1044

11-
<div className="p-4">
12-
<div className="flex items-center space-x-2 mb-4">
13-
<div
14-
className={`w-2 h-2 rounded-full ${
15-
connectionStatus === "connected"
16-
? "bg-green-500"
17-
: connectionStatus === "error"
18-
? "bg-red-500"
19-
: "bg-gray-500"
20-
}`}
21-
/>
22-
<span className="text-sm text-gray-600">
23-
{connectionStatus === "connected"
24-
? "Connected"
25-
: connectionStatus === "error"
26-
? "Connection Error"
27-
: "Disconnected"}
28-
</span>
45+
return (
46+
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
47+
<div className="flex items-center p-4 border-b border-gray-200">
48+
<Settings className="w-6 h-6 text-gray-500" />
49+
<h1 className="ml-2 text-lg font-semibold">MCP Inspector</h1>
2950
</div>
3051

31-
<Button variant="outline" className="w-full justify-start">
32-
<Settings className="w-4 h-4 mr-2" />
33-
Connection Settings
34-
</Button>
52+
<div className="p-4 flex-1 overflow-auto">
53+
<div className="space-y-4">
54+
<div className="space-y-2">
55+
<label className="text-sm font-medium">Transport Type</label>
56+
<Select
57+
value={transportType}
58+
onValueChange={(value: "stdio" | "sse") =>
59+
setTransportType(value)
60+
}
61+
>
62+
<SelectTrigger>
63+
<SelectValue placeholder="Select transport type" />
64+
</SelectTrigger>
65+
<SelectContent>
66+
<SelectItem value="stdio">STDIO</SelectItem>
67+
<SelectItem value="sse">SSE</SelectItem>
68+
</SelectContent>
69+
</Select>
70+
</div>
71+
{transportType === "stdio" ? (
72+
<>
73+
<div className="space-y-2">
74+
<label className="text-sm font-medium">Command</label>
75+
<Input
76+
placeholder="Command"
77+
value={command}
78+
onChange={(e) => setCommand(e.target.value)}
79+
/>
80+
</div>
81+
<div className="space-y-2">
82+
<label className="text-sm font-medium">Arguments</label>
83+
<Input
84+
placeholder="Arguments (space-separated)"
85+
value={args}
86+
onChange={(e) => setArgs(e.target.value)}
87+
/>
88+
</div>
89+
</>
90+
) : (
91+
<div className="space-y-2">
92+
<label className="text-sm font-medium">URL</label>
93+
<Input
94+
placeholder="URL"
95+
value={url}
96+
onChange={(e) => setUrl(e.target.value)}
97+
/>
98+
</div>
99+
)}
100+
{transportType === "stdio" && (
101+
<div className="space-y-2">
102+
<Button
103+
variant="outline"
104+
onClick={() => setShowEnvVars(!showEnvVars)}
105+
className="flex items-center w-full"
106+
>
107+
{showEnvVars ? (
108+
<ChevronDown className="w-4 h-4 mr-2" />
109+
) : (
110+
<ChevronRight className="w-4 h-4 mr-2" />
111+
)}
112+
Environment Variables
113+
</Button>
114+
{showEnvVars && (
115+
<div className="space-y-2">
116+
{Object.entries(env).map(([key, value]) => (
117+
<div key={key} className="grid grid-cols-[1fr,auto] gap-2">
118+
<div className="space-y-1">
119+
<Input
120+
placeholder="Key"
121+
value={key}
122+
onChange={(e) => {
123+
const newEnv = { ...env };
124+
newEnv[e.target.value] = value;
125+
setEnv(newEnv);
126+
}}
127+
/>
128+
<Input
129+
placeholder="Value"
130+
value={value}
131+
onChange={(e) => {
132+
const newEnv = { ...env };
133+
newEnv[key] = e.target.value;
134+
setEnv(newEnv);
135+
}}
136+
/>
137+
</div>
138+
<Button
139+
variant="destructive"
140+
onClick={() => {
141+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
142+
const { [key]: removed, ...rest } = env;
143+
setEnv(rest);
144+
}}
145+
>
146+
Remove
147+
</Button>
148+
</div>
149+
))}
150+
<Button
151+
variant="outline"
152+
onClick={() => {
153+
const newEnv = { ...env };
154+
newEnv[""] = "";
155+
setEnv(newEnv);
156+
}}
157+
>
158+
Add Environment Variable
159+
</Button>
160+
</div>
161+
)}
162+
</div>
163+
)}
164+
165+
<div className="space-y-2">
166+
<Button className="w-full" onClick={onConnect}>
167+
<Play className="w-4 h-4 mr-2" />
168+
Connect
169+
</Button>
170+
171+
<div className="flex items-center justify-center space-x-2 mb-4">
172+
<div
173+
className={`w-2 h-2 rounded-full ${
174+
connectionStatus === "connected"
175+
? "bg-green-500"
176+
: connectionStatus === "error"
177+
? "bg-red-500"
178+
: "bg-gray-500"
179+
}`}
180+
/>
181+
<span className="text-sm text-gray-600">
182+
{connectionStatus === "connected"
183+
? "Connected"
184+
: connectionStatus === "error"
185+
? "Connection Error"
186+
: "Disconnected"}
187+
</span>
188+
</div>
189+
</div>
190+
</div>
191+
</div>
35192
</div>
36-
</div>
37-
);
193+
);
194+
};
38195

39196
export default Sidebar;

0 commit comments

Comments
 (0)