Merge branch 'main' into fix-required

This commit is contained in:
Ola Hungerford 2025-06-04 19:59:52 -07:00 • committed by GitHub
commit e28e08d37d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 114 additions and 28 deletions

View file

@ -30,7 +30,10 @@ import React, {
useState,
} from "react";
import { useConnection } from "./lib/hooks/useConnection";
import { useDraggablePane } from "./lib/hooks/useDraggablePane";
import {
useDraggablePane,
useDraggableSidebar,
} from "./lib/hooks/useDraggablePane";
import { StdErrNotification } from "./lib/notificationTypes";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
@ -154,6 +157,11 @@ const App = () => {
const progressTokenRef = useRef(0);
const { height: historyPaneHeight, handleDragStart } = useDraggablePane(300);
const {
width: sidebarWidth,
isDragging: isSidebarDragging,
handleDragStart: handleSidebarDragStart,
} = useDraggableSidebar(320);
const {
connectionStatus,
@ -607,32 +615,58 @@ const App = () => {
return (
<div className="flex h-screen bg-background">
<Sidebar
connectionStatus={connectionStatus}
transportType={transportType}
setTransportType={setTransportType}
command={command}
setCommand={setCommand}
args={args}
setArgs={setArgs}
sseUrl={sseUrl}
setSseUrl={setSseUrl}
env={env}
setEnv={setEnv}
config={config}
setConfig={setConfig}
bearerToken={bearerToken}
setBearerToken={setBearerToken}
headerName={headerName}
setHeaderName={setHeaderName}
onConnect={connectMcpServer}
onDisconnect={disconnectMcpServer}
stdErrNotifications={stdErrNotifications}
logLevel={logLevel}
sendLogLevelRequest={sendLogLevelRequest}
loggingSupported={!!serverCapabilities?.logging || false}
clearStdErrNotifications={clearStdErrNotifications}
/>
<div
style={{
width: sidebarWidth,
minWidth: 200,
maxWidth: 600,
transition: isSidebarDragging ? "none" : "width 0.15s",
}}
className="bg-card border-r border-border flex flex-col h-full relative"
>
<Sidebar
connectionStatus={connectionStatus}
transportType={transportType}
setTransportType={setTransportType}
command={command}
setCommand={setCommand}
args={args}
setArgs={setArgs}
sseUrl={sseUrl}
setSseUrl={setSseUrl}
env={env}
setEnv={setEnv}
config={config}
setConfig={setConfig}
bearerToken={bearerToken}
setBearerToken={setBearerToken}
headerName={headerName}
setHeaderName={setHeaderName}
onConnect={connectMcpServer}
onDisconnect={disconnectMcpServer}
stdErrNotifications={stdErrNotifications}
logLevel={logLevel}
sendLogLevelRequest={sendLogLevelRequest}
loggingSupported={!!serverCapabilities?.logging || false}
clearStdErrNotifications={clearStdErrNotifications}
/>
{/* Drag handle for resizing sidebar */}
<div
onMouseDown={handleSidebarDragStart}
style={{
cursor: "col-resize",
position: "absolute",
top: 0,
right: 0,
width: 6,
height: "100%",
zIndex: 10,
background: isSidebarDragging ? "rgba(0,0,0,0.08)" : "transparent",
}}
aria-label="Resize sidebar"
data-testid="sidebar-drag-handle"
/>
</div>
<div className="flex-1 flex flex-col overflow-hidden">
<div className="flex-1 overflow-auto">
{mcpClient ? (

View file

@ -214,7 +214,7 @@ const Sidebar = ({
}, [generateMCPServerFile, toast, reportError]);
return (
<div className="w-80 bg-card border-r border-border flex flex-col h-full">
<div className="bg-card border-r border-border flex flex-col h-full">
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-border">
<div className="flex items-center">
<h1 className="ml-2 text-lg font-semibold">

View file

@ -51,3 +51,55 @@ export function useDraggablePane(initialHeight: number) {
handleDragStart,
};
}
export function useDraggableSidebar(initialWidth: number) {
const [width, setWidth] = useState(initialWidth);
const [isDragging, setIsDragging] = useState(false);
const dragStartX = useRef<number>(0);
const dragStartWidth = useRef<number>(0);
const handleDragStart = useCallback(
(e: React.MouseEvent) => {
setIsDragging(true);
dragStartX.current = e.clientX;
dragStartWidth.current = width;
document.body.style.userSelect = "none";
},
[width],
);
const handleDragMove = useCallback(
(e: MouseEvent) => {
if (!isDragging) return;
const deltaX = e.clientX - dragStartX.current;
const newWidth = Math.max(
200,
Math.min(600, dragStartWidth.current + deltaX),
);
setWidth(newWidth);
},
[isDragging],
);
const handleDragEnd = useCallback(() => {
setIsDragging(false);
document.body.style.userSelect = "";
}, []);
useEffect(() => {
if (isDragging) {
window.addEventListener("mousemove", handleDragMove);
window.addEventListener("mouseup", handleDragEnd);
return () => {
window.removeEventListener("mousemove", handleDragMove);
window.removeEventListener("mouseup", handleDragEnd);
};
}
}, [isDragging, handleDragMove, handleDragEnd]);
return {
width,
isDragging,
handleDragStart,
};
}