adding fixes as buttons were not visible for streamable-http transport type, as per PR review comment
This commit is contained in:
@@ -119,13 +119,22 @@ const Sidebar = ({
|
||||
args: args.trim() ? args.split(/\s+/) : [],
|
||||
env: { ...env },
|
||||
};
|
||||
} else {
|
||||
}
|
||||
if (transportType === "sse") {
|
||||
return {
|
||||
type: "sse",
|
||||
url: sseUrl,
|
||||
note: "For SSE connections, add this URL directly in Client",
|
||||
};
|
||||
}
|
||||
if (transportType === "streamable-http") {
|
||||
return {
|
||||
type: "streamable-http",
|
||||
url: sseUrl,
|
||||
note: "For Streamable HTTP connections, add this URL directly in Client",
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}, [transportType, command, args, env, sseUrl]);
|
||||
|
||||
// Memoized config entry generator
|
||||
@@ -266,44 +275,6 @@ const Sidebar = ({
|
||||
className="font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2 mt-2">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCopyServerEntry}
|
||||
className="w-full"
|
||||
>
|
||||
{copiedServerEntry ? (
|
||||
<CheckCheck className="h-4 w-4 mr-2" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Server Entry
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Copy Server Entry</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCopyServerFile}
|
||||
className="w-full"
|
||||
>
|
||||
{copiedServerFile ? (
|
||||
<CheckCheck className="h-4 w-4 mr-2" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Servers File
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Copy Servers File</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -319,22 +290,6 @@ const Sidebar = ({
|
||||
className="font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full mt-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCopyServerFile}
|
||||
className="w-full"
|
||||
title="Copy SSE URL Configuration"
|
||||
>
|
||||
{copiedServerFile ? (
|
||||
<CheckCheck className="h-4 w-4 mr-2" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Copy Servers File
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -382,6 +337,7 @@ const Sidebar = ({
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{transportType === "stdio" && (
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
@@ -507,6 +463,46 @@ const Sidebar = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Always show both copy buttons for all transport types */}
|
||||
<div className="grid grid-cols-2 gap-2 mt-2">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCopyServerEntry}
|
||||
className="w-full"
|
||||
>
|
||||
{copiedServerEntry ? (
|
||||
<CheckCheck className="h-4 w-4 mr-2" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Server Entry
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Copy Server Entry</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleCopyServerFile}
|
||||
className="w-full"
|
||||
>
|
||||
{copiedServerFile ? (
|
||||
<CheckCheck className="h-4 w-4 mr-2" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Servers File
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Copy Servers File</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
{/* Configuration */}
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
|
||||
@@ -649,6 +649,31 @@ describe("Sidebar Environment Variables", () => {
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
const getCopyButtons = () => {
|
||||
return {
|
||||
serverEntry: screen.getByRole("button", { name: /server entry/i }),
|
||||
serversFile: screen.getByRole("button", { name: /servers file/i }),
|
||||
};
|
||||
};
|
||||
|
||||
it("should render both copy buttons for all transport types", () => {
|
||||
["stdio", "sse", "streamable-http"].forEach((transportType) => {
|
||||
renderSidebar({ transportType });
|
||||
// There should be exactly one Server Entry and one Servers File button per render
|
||||
const serverEntryButtons = screen.getAllByRole("button", {
|
||||
name: /server entry/i,
|
||||
});
|
||||
const serversFileButtons = screen.getAllByRole("button", {
|
||||
name: /servers file/i,
|
||||
});
|
||||
expect(serverEntryButtons).toHaveLength(1);
|
||||
expect(serversFileButtons).toHaveLength(1);
|
||||
// Clean up DOM for next iteration
|
||||
// (Testing Library's render does not auto-unmount in a loop)
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
});
|
||||
|
||||
it("should copy server entry configuration to clipboard for STDIO transport", async () => {
|
||||
const command = "node";
|
||||
const args = "--inspect server.js";
|
||||
@@ -661,20 +686,13 @@ describe("Sidebar Environment Variables", () => {
|
||||
env,
|
||||
});
|
||||
|
||||
// Use act to properly wrap the clipboard operations
|
||||
await act(async () => {
|
||||
const copyServerEntryButton = screen.getByRole("button", {
|
||||
name: /server entry/i,
|
||||
});
|
||||
fireEvent.click(copyServerEntryButton);
|
||||
|
||||
// Fast-forward timers to handle the setTimeout
|
||||
const { serverEntry } = getCopyButtons();
|
||||
fireEvent.click(serverEntry);
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Check clipboard API was called with the correct configuration
|
||||
expect(mockClipboardWrite).toHaveBeenCalledTimes(1);
|
||||
|
||||
const expectedConfig = JSON.stringify(
|
||||
{
|
||||
command,
|
||||
@@ -684,7 +702,6 @@ describe("Sidebar Environment Variables", () => {
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
expect(mockClipboardWrite).toHaveBeenCalledWith(expectedConfig);
|
||||
});
|
||||
|
||||
@@ -701,18 +718,12 @@ describe("Sidebar Environment Variables", () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
const copyServersFileButton = screen.getByRole("button", {
|
||||
name: /servers file/i,
|
||||
});
|
||||
fireEvent.click(copyServersFileButton);
|
||||
|
||||
// Fast-forward timers to handle the setTimeout
|
||||
const { serversFile } = getCopyButtons();
|
||||
fireEvent.click(serversFile);
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Check clipboard API was called with the correct configuration
|
||||
expect(mockClipboardWrite).toHaveBeenCalledTimes(1);
|
||||
|
||||
const expectedConfig = JSON.stringify(
|
||||
{
|
||||
mcpServers: {
|
||||
@@ -726,31 +737,43 @@ describe("Sidebar Environment Variables", () => {
|
||||
null,
|
||||
2,
|
||||
);
|
||||
expect(mockClipboardWrite).toHaveBeenCalledWith(expectedConfig);
|
||||
});
|
||||
|
||||
it("should copy server entry configuration to clipboard for SSE transport", async () => {
|
||||
const sseUrl = "http://localhost:3000/events";
|
||||
renderSidebar({ transportType: "sse", sseUrl });
|
||||
|
||||
await act(async () => {
|
||||
const { serverEntry } = getCopyButtons();
|
||||
fireEvent.click(serverEntry);
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
expect(mockClipboardWrite).toHaveBeenCalledTimes(1);
|
||||
const expectedConfig = JSON.stringify(
|
||||
{
|
||||
type: "sse",
|
||||
url: sseUrl,
|
||||
note: "For SSE connections, add this URL directly in Client",
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
expect(mockClipboardWrite).toHaveBeenCalledWith(expectedConfig);
|
||||
});
|
||||
|
||||
it("should copy servers file configuration to clipboard for SSE transport", async () => {
|
||||
const sseUrl = "http://localhost:3000/events";
|
||||
|
||||
renderSidebar({
|
||||
transportType: "sse",
|
||||
sseUrl,
|
||||
});
|
||||
renderSidebar({ transportType: "sse", sseUrl });
|
||||
|
||||
await act(async () => {
|
||||
const copyServersFileButton = screen.getByRole("button", {
|
||||
name: /servers file/i,
|
||||
});
|
||||
fireEvent.click(copyServersFileButton);
|
||||
|
||||
// Fast-forward timers to handle the setTimeout
|
||||
const { serversFile } = getCopyButtons();
|
||||
fireEvent.click(serversFile);
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Check clipboard API was called with the correct configuration
|
||||
expect(mockClipboardWrite).toHaveBeenCalledTimes(1);
|
||||
|
||||
const expectedConfig = JSON.stringify(
|
||||
{
|
||||
mcpServers: {
|
||||
@@ -764,7 +787,56 @@ describe("Sidebar Environment Variables", () => {
|
||||
null,
|
||||
2,
|
||||
);
|
||||
expect(mockClipboardWrite).toHaveBeenCalledWith(expectedConfig);
|
||||
});
|
||||
|
||||
it("should copy server entry configuration to clipboard for streamable-http transport", async () => {
|
||||
const sseUrl = "http://localhost:3001/sse";
|
||||
renderSidebar({ transportType: "streamable-http", sseUrl });
|
||||
|
||||
await act(async () => {
|
||||
const { serverEntry } = getCopyButtons();
|
||||
fireEvent.click(serverEntry);
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
expect(mockClipboardWrite).toHaveBeenCalledTimes(1);
|
||||
const expectedConfig = JSON.stringify(
|
||||
{
|
||||
type: "streamable-http",
|
||||
url: sseUrl,
|
||||
note: "For Streamable HTTP connections, add this URL directly in Client",
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
expect(mockClipboardWrite).toHaveBeenCalledWith(expectedConfig);
|
||||
});
|
||||
|
||||
it("should copy servers file configuration to clipboard for streamable-http transport", async () => {
|
||||
const sseUrl = "http://localhost:3001/sse";
|
||||
renderSidebar({ transportType: "streamable-http", sseUrl });
|
||||
|
||||
await act(async () => {
|
||||
const { serversFile } = getCopyButtons();
|
||||
fireEvent.click(serversFile);
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
expect(mockClipboardWrite).toHaveBeenCalledTimes(1);
|
||||
const expectedConfig = JSON.stringify(
|
||||
{
|
||||
mcpServers: {
|
||||
"default-server": {
|
||||
type: "streamable-http",
|
||||
url: sseUrl,
|
||||
note: "For Streamable HTTP connections, add this URL directly in Client",
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
);
|
||||
expect(mockClipboardWrite).toHaveBeenCalledWith(expectedConfig);
|
||||
});
|
||||
|
||||
@@ -779,18 +851,12 @@ describe("Sidebar Environment Variables", () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
const copyServerEntryButton = screen.getByRole("button", {
|
||||
name: /server entry/i,
|
||||
});
|
||||
fireEvent.click(copyServerEntryButton);
|
||||
|
||||
// Fast-forward timers to handle the setTimeout
|
||||
const { serverEntry } = getCopyButtons();
|
||||
fireEvent.click(serverEntry);
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Check clipboard API was called with empty args array
|
||||
expect(mockClipboardWrite).toHaveBeenCalledTimes(1);
|
||||
|
||||
const expectedConfig = JSON.stringify(
|
||||
{
|
||||
command,
|
||||
@@ -800,7 +866,6 @@ describe("Sidebar Environment Variables", () => {
|
||||
null,
|
||||
2,
|
||||
);
|
||||
|
||||
expect(mockClipboardWrite).toHaveBeenCalledWith(expectedConfig);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user