mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Add mock data and gui
This commit is contained in:
@@ -1,10 +1,120 @@
|
||||
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||
import {
|
||||
VSCodeButton,
|
||||
VSCodeDivider,
|
||||
VSCodeTextArea,
|
||||
VSCodeTextField,
|
||||
VSCodeTag,
|
||||
VSCodePanelTab,
|
||||
VSCodePanelView,
|
||||
VSCodeDataGrid,
|
||||
VSCodeDataGridRow,
|
||||
VSCodeDataGridCell,
|
||||
VSCodePanels,
|
||||
} from "@vscode/webview-ui-toolkit/react"
|
||||
import { useState } from "react"
|
||||
|
||||
type McpServer = {
|
||||
name: string
|
||||
config: string // JSON config
|
||||
status: "connected" | "connecting" | "disconnected"
|
||||
error?: string
|
||||
tools?: any[] // We'll type this properly later
|
||||
resources?: any[] // We'll type this properly later
|
||||
}
|
||||
|
||||
type McpViewProps = {
|
||||
onDone: () => void
|
||||
}
|
||||
|
||||
const McpView = ({ onDone }: McpViewProps) => {
|
||||
const [isAdding, setIsAdding] = useState(false)
|
||||
const [servers, setServers] = useState<McpServer[]>([
|
||||
// Add some mock servers for testing
|
||||
{
|
||||
name: "local-tools",
|
||||
config: JSON.stringify({
|
||||
mcpServers: {
|
||||
"local-tools": {
|
||||
command: "npx",
|
||||
args: ["-y", "@modelcontextprotocol/server-tools"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
status: "connected",
|
||||
tools: [
|
||||
{
|
||||
name: "execute_command",
|
||||
description: "Run a shell command on the local system",
|
||||
},
|
||||
{
|
||||
name: "read_file",
|
||||
description: "Read contents of a file from the filesystem",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "postgres-db",
|
||||
config: JSON.stringify({
|
||||
mcpServers: {
|
||||
"postgres-db": {
|
||||
command: "npx",
|
||||
args: ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
status: "disconnected",
|
||||
error: "Failed to connect to database: Connection refused",
|
||||
},
|
||||
{
|
||||
name: "github-tools",
|
||||
config: JSON.stringify({
|
||||
mcpServers: {
|
||||
"github-tools": {
|
||||
command: "npx",
|
||||
args: ["-y", "@modelcontextprotocol/server-github"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
status: "connecting",
|
||||
resources: [
|
||||
{
|
||||
uri: "github://repo/issues",
|
||||
name: "Repository Issues",
|
||||
},
|
||||
{
|
||||
uri: "github://repo/pulls",
|
||||
name: "Pull Requests",
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
const [configInput, setConfigInput] = useState("")
|
||||
|
||||
const handleAddServer = () => {
|
||||
try {
|
||||
const config = JSON.parse(configInput)
|
||||
const serverName = Object.keys(config.mcpServers)[0]
|
||||
|
||||
setServers((prev) => [
|
||||
...prev,
|
||||
{
|
||||
name: serverName,
|
||||
config: configInput,
|
||||
status: "connecting",
|
||||
},
|
||||
])
|
||||
|
||||
setIsAdding(false)
|
||||
setConfigInput("")
|
||||
|
||||
// Here you would trigger the actual server connection
|
||||
// and update its status/tools/resources accordingly
|
||||
} catch (e) {
|
||||
// Handle invalid JSON
|
||||
console.error("Invalid server configuration:", e)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -24,14 +134,256 @@ const McpView = ({ onDone }: McpViewProps) => {
|
||||
alignItems: "center",
|
||||
padding: "10px 17px 10px 20px",
|
||||
}}>
|
||||
<h3 style={{ color: "var(--vscode-foreground)", margin: 0 }}>MCP</h3>
|
||||
<h3 style={{ color: "var(--vscode-foreground)", margin: 0 }}>MCP Servers</h3>
|
||||
<VSCodeButton onClick={onDone}>Done</VSCodeButton>
|
||||
</div>
|
||||
<div style={{ padding: "20px", display: "flex", justifyContent: "center" }}>
|
||||
<VSCodeButton>Add Server</VSCodeButton>
|
||||
<p style={{ padding: "0 20px", color: "var(--vscode-foreground)", fontSize: "13px" }}>
|
||||
MCP (Model Context Protocol) enables AI models to access external tools and data through standardized
|
||||
interfaces. Add MCP servers to extend Claude's capabilities with custom functionality and real-time data
|
||||
access.
|
||||
</p>
|
||||
|
||||
{/* Server List */}
|
||||
<div style={{ flex: 1, overflow: "auto", padding: "0 20px" }}>
|
||||
{servers.map((server) => (
|
||||
<ServerRow key={server.name} server={server} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Add Server UI */}
|
||||
<div style={{ padding: "20px" }}>
|
||||
{isAdding ? (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
|
||||
<VSCodeTextArea
|
||||
rows={4}
|
||||
placeholder='{"mcpServers": {"server-name": {"command": "...", "args": [...]}}}'
|
||||
value={configInput}
|
||||
onChange={(e) => setConfigInput((e.target as HTMLTextAreaElement).value)}
|
||||
/>
|
||||
<div style={{ display: "flex", gap: "10px" }}>
|
||||
<VSCodeButton style={{ flex: 1 }} onClick={handleAddServer}>
|
||||
Add Server
|
||||
</VSCodeButton>
|
||||
<VSCodeButton style={{ flex: 1 }} appearance="secondary" onClick={() => setIsAdding(false)}>
|
||||
Cancel
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<VSCodeButton style={{ width: "100%" }} onClick={() => setIsAdding(true)}>
|
||||
<span className="codicon codicon-add" style={{ marginRight: "6px" }}></span>
|
||||
Add MCP Server
|
||||
</VSCodeButton>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Server Row Component
|
||||
const ServerRow = ({ server }: { server: McpServer }) => {
|
||||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
const [editConfig, setEditConfig] = useState(server.config)
|
||||
|
||||
const getStatusColor = () => {
|
||||
switch (server.status) {
|
||||
case "connected":
|
||||
return "var(--vscode-testing-iconPassed)"
|
||||
case "connecting":
|
||||
return "var(--vscode-charts-yellow)"
|
||||
case "disconnected":
|
||||
return "var(--vscode-testing-iconFailed)"
|
||||
}
|
||||
}
|
||||
|
||||
const handleSaveConfig = () => {
|
||||
try {
|
||||
JSON.parse(editConfig) // Validate JSON
|
||||
// Here you would update the server config
|
||||
setIsEditing(false)
|
||||
} catch (e) {
|
||||
console.error("Invalid JSON config:", e)
|
||||
}
|
||||
}
|
||||
|
||||
// Don't allow expansion if server has error
|
||||
const handleRowClick = () => {
|
||||
if (!server.error) {
|
||||
setIsExpanded(!isExpanded)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
padding: "8px",
|
||||
background: "var(--vscode-list-hoverBackground)",
|
||||
cursor: server.error ? "default" : "pointer",
|
||||
borderRadius: isExpanded || server.error ? "4px 4px 0 0" : "4px",
|
||||
}}
|
||||
onClick={handleRowClick}>
|
||||
{!server.error && (
|
||||
<span
|
||||
className={`codicon codicon-chevron-${isExpanded ? "down" : "right"}`}
|
||||
style={{ marginRight: "8px" }}
|
||||
/>
|
||||
)}
|
||||
<span style={{ flex: 1 }}>{server.name}</span>
|
||||
<div
|
||||
style={{
|
||||
width: "8px",
|
||||
height: "8px",
|
||||
borderRadius: "50%",
|
||||
background: getStatusColor(),
|
||||
marginLeft: "8px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{server.error ? (
|
||||
<div
|
||||
style={{
|
||||
padding: "8px",
|
||||
fontSize: "13px",
|
||||
color: "var(--vscode-testing-iconFailed)",
|
||||
background: "var(--vscode-list-hoverBackground)",
|
||||
borderRadius: "0 0 4px 4px",
|
||||
}}>
|
||||
{server.error}
|
||||
</div>
|
||||
) : (
|
||||
isExpanded && (
|
||||
<div
|
||||
style={{
|
||||
background: "var(--vscode-list-hoverBackground)",
|
||||
padding: "0 12px 12px 12px",
|
||||
fontSize: "13px",
|
||||
borderRadius: "0 0 4px 4px",
|
||||
}}>
|
||||
<VSCodePanels>
|
||||
<VSCodePanelTab id="tools">Tools ({server.tools?.length || 0})</VSCodePanelTab>
|
||||
<VSCodePanelTab id="resources">Resources ({server.resources?.length || 0})</VSCodePanelTab>
|
||||
|
||||
<VSCodePanelView id="tools-view">
|
||||
{server.tools && server.tools.length > 0 ? (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "3px" }}>
|
||||
{server.tools.map((tool) => (
|
||||
<div
|
||||
key={tool.name}
|
||||
style={{
|
||||
padding: "8px 0",
|
||||
}}>
|
||||
<div style={{ display: "flex" }}>
|
||||
<span
|
||||
className="codicon codicon-symbol-method"
|
||||
style={{ marginRight: "6px" }}></span>
|
||||
<span style={{ fontWeight: 500 }}>{tool.name}</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
marginLeft: "0px",
|
||||
marginTop: "4px",
|
||||
opacity: 0.8,
|
||||
fontSize: "12px",
|
||||
}}>
|
||||
{tool.description}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ padding: "10px 0", color: "var(--vscode-descriptionForeground)" }}>
|
||||
No tools found
|
||||
</div>
|
||||
)}
|
||||
</VSCodePanelView>
|
||||
|
||||
{/* Resources Panel View */}
|
||||
<VSCodePanelView id="resources-view">
|
||||
{server.resources && server.resources.length > 0 ? (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "3px" }}>
|
||||
{server.resources.map((resource) => (
|
||||
<div
|
||||
key={resource.uri}
|
||||
style={{
|
||||
padding: "8px 0",
|
||||
}}>
|
||||
<div style={{ display: "flex" }}>
|
||||
<span
|
||||
className="codicon codicon-symbol-file"
|
||||
style={{ marginRight: "6px" }}></span>
|
||||
<span style={{ fontWeight: 500 }}>{resource.name}</span>
|
||||
</div>
|
||||
<div style={{ marginTop: "6px", fontSize: "12px" }}>
|
||||
<code
|
||||
style={{
|
||||
color: "var(--vscode-textPreformat-foreground)",
|
||||
background: "var(--vscode-textPreformat-background)",
|
||||
padding: "2px 4px",
|
||||
borderRadius: "3px",
|
||||
}}>
|
||||
{resource.uri}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ padding: "10px 0", color: "var(--vscode-descriptionForeground)" }}>
|
||||
No resources found
|
||||
</div>
|
||||
)}
|
||||
</VSCodePanelView>
|
||||
</VSCodePanels>
|
||||
|
||||
{/* Edit/Remove Buttons */}
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: "8px", marginTop: "0px" }}>
|
||||
{isEditing ? (
|
||||
<>
|
||||
<VSCodeTextArea
|
||||
value={editConfig}
|
||||
onChange={(e) => setEditConfig((e.target as HTMLTextAreaElement).value)}
|
||||
style={{ width: "100%" }}
|
||||
/>
|
||||
<div style={{ display: "flex", gap: "8px" }}>
|
||||
<VSCodeButton onClick={handleSaveConfig} style={{ flex: 1 }}>
|
||||
Save
|
||||
</VSCodeButton>
|
||||
<VSCodeButton
|
||||
appearance="secondary"
|
||||
onClick={() => setIsEditing(false)}
|
||||
style={{ flex: 1 }}>
|
||||
Cancel
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ display: "flex", gap: "8px" }}>
|
||||
<VSCodeButton
|
||||
appearance="secondary"
|
||||
onClick={() => setIsEditing(true)}
|
||||
style={{ flex: 1 }}>
|
||||
Edit
|
||||
</VSCodeButton>
|
||||
<VSCodeButton
|
||||
appearance="secondary"
|
||||
style={{
|
||||
flex: 1,
|
||||
}}>
|
||||
Remove
|
||||
</VSCodeButton>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default McpView
|
||||
|
||||
Reference in New Issue
Block a user