Merge branch 'main' into fix-reconnect
This commit is contained in:
@@ -12,6 +12,7 @@ interface JsonViewProps {
|
||||
initialExpandDepth?: number;
|
||||
className?: string;
|
||||
withCopyButton?: boolean;
|
||||
isError?: boolean;
|
||||
}
|
||||
|
||||
const JsonView = memo(
|
||||
@@ -21,6 +22,7 @@ const JsonView = memo(
|
||||
initialExpandDepth = 3,
|
||||
className,
|
||||
withCopyButton = true,
|
||||
isError = false,
|
||||
}: JsonViewProps) => {
|
||||
const { toast } = useToast();
|
||||
const [copied, setCopied] = useState(false);
|
||||
@@ -86,6 +88,7 @@ const JsonView = memo(
|
||||
name={name}
|
||||
depth={0}
|
||||
initialExpandDepth={initialExpandDepth}
|
||||
isError={isError}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,17 +103,25 @@ interface JsonNodeProps {
|
||||
name?: string;
|
||||
depth: number;
|
||||
initialExpandDepth: number;
|
||||
isError?: boolean;
|
||||
}
|
||||
|
||||
const JsonNode = memo(
|
||||
({ data, name, depth = 0, initialExpandDepth }: JsonNodeProps) => {
|
||||
({
|
||||
data,
|
||||
name,
|
||||
depth = 0,
|
||||
initialExpandDepth,
|
||||
isError = false,
|
||||
}: JsonNodeProps) => {
|
||||
const [isExpanded, setIsExpanded] = useState(depth < initialExpandDepth);
|
||||
const [typeStyleMap] = useState<Record<string, string>>({
|
||||
number: "text-blue-600",
|
||||
boolean: "text-amber-600",
|
||||
null: "text-purple-600",
|
||||
undefined: "text-gray-600",
|
||||
string: "text-green-600 break-all whitespace-pre-wrap",
|
||||
string: "text-green-600 group-hover:text-green-500",
|
||||
error: "text-red-600 group-hover:text-red-500",
|
||||
default: "text-gray-700",
|
||||
});
|
||||
const dataType = getDataType(data);
|
||||
@@ -214,7 +225,14 @@ const JsonNode = memo(
|
||||
{name}:
|
||||
</span>
|
||||
)}
|
||||
<pre className={typeStyleMap.string}>"{value}"</pre>
|
||||
<pre
|
||||
className={clsx(
|
||||
typeStyleMap.string,
|
||||
"break-all whitespace-pre-wrap",
|
||||
)}
|
||||
>
|
||||
"{value}"
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -228,8 +246,8 @@ const JsonNode = memo(
|
||||
)}
|
||||
<pre
|
||||
className={clsx(
|
||||
typeStyleMap.string,
|
||||
"cursor-pointer group-hover:text-green-500",
|
||||
isError ? typeStyleMap.error : typeStyleMap.string,
|
||||
"cursor-pointer break-all whitespace-pre-wrap",
|
||||
)}
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
title={isExpanded ? "Click to collapse" : "Click to expand"}
|
||||
|
||||
@@ -103,14 +103,19 @@ const Sidebar = ({
|
||||
<div className="p-4 flex-1 overflow-auto">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Transport Type</label>
|
||||
<label
|
||||
className="text-sm font-medium"
|
||||
htmlFor="transport-type-select"
|
||||
>
|
||||
Transport Type
|
||||
</label>
|
||||
<Select
|
||||
value={transportType}
|
||||
onValueChange={(value: "stdio" | "sse") =>
|
||||
setTransportType(value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger id="transport-type-select">
|
||||
<SelectValue placeholder="Select transport type" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -123,8 +128,11 @@ const Sidebar = ({
|
||||
{transportType === "stdio" ? (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Command</label>
|
||||
<label className="text-sm font-medium" htmlFor="command-input">
|
||||
Command
|
||||
</label>
|
||||
<Input
|
||||
id="command-input"
|
||||
placeholder="Command"
|
||||
value={command}
|
||||
onChange={(e) => setCommand(e.target.value)}
|
||||
@@ -132,8 +140,14 @@ const Sidebar = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Arguments</label>
|
||||
<label
|
||||
className="text-sm font-medium"
|
||||
htmlFor="arguments-input"
|
||||
>
|
||||
Arguments
|
||||
</label>
|
||||
<Input
|
||||
id="arguments-input"
|
||||
placeholder="Arguments (space-separated)"
|
||||
value={args}
|
||||
onChange={(e) => setArgs(e.target.value)}
|
||||
@@ -144,8 +158,11 @@ const Sidebar = ({
|
||||
) : (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">URL</label>
|
||||
<label className="text-sm font-medium" htmlFor="sse-url-input">
|
||||
URL
|
||||
</label>
|
||||
<Input
|
||||
id="sse-url-input"
|
||||
placeholder="URL"
|
||||
value={sseUrl}
|
||||
onChange={(e) => setSseUrl(e.target.value)}
|
||||
@@ -157,6 +174,7 @@ const Sidebar = ({
|
||||
variant="outline"
|
||||
onClick={() => setShowBearerToken(!showBearerToken)}
|
||||
className="flex items-center w-full"
|
||||
aria-expanded={showBearerToken}
|
||||
>
|
||||
{showBearerToken ? (
|
||||
<ChevronDown className="w-4 h-4 mr-2" />
|
||||
@@ -167,8 +185,14 @@ const Sidebar = ({
|
||||
</Button>
|
||||
{showBearerToken && (
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Bearer Token</label>
|
||||
<label
|
||||
className="text-sm font-medium"
|
||||
htmlFor="bearer-token-input"
|
||||
>
|
||||
Bearer Token
|
||||
</label>
|
||||
<Input
|
||||
id="bearer-token-input"
|
||||
placeholder="Bearer Token"
|
||||
value={bearerToken}
|
||||
onChange={(e) => setBearerToken(e.target.value)}
|
||||
@@ -187,6 +211,7 @@ const Sidebar = ({
|
||||
onClick={() => setShowEnvVars(!showEnvVars)}
|
||||
className="flex items-center w-full"
|
||||
data-testid="env-vars-button"
|
||||
aria-expanded={showEnvVars}
|
||||
>
|
||||
{showEnvVars ? (
|
||||
<ChevronDown className="w-4 h-4 mr-2" />
|
||||
@@ -201,6 +226,7 @@ const Sidebar = ({
|
||||
<div key={idx} className="space-y-2 pb-4">
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
aria-label={`Environment variable key ${idx + 1}`}
|
||||
placeholder="Key"
|
||||
value={key}
|
||||
onChange={(e) => {
|
||||
@@ -243,6 +269,7 @@ const Sidebar = ({
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
aria-label={`Environment variable value ${idx + 1}`}
|
||||
type={shownEnvVars.has(key) ? "text" : "password"}
|
||||
placeholder="Value"
|
||||
value={value}
|
||||
@@ -309,6 +336,7 @@ const Sidebar = ({
|
||||
onClick={() => setShowConfig(!showConfig)}
|
||||
className="flex items-center w-full"
|
||||
data-testid="config-button"
|
||||
aria-expanded={showConfig}
|
||||
>
|
||||
{showConfig ? (
|
||||
<ChevronDown className="w-4 h-4 mr-2" />
|
||||
@@ -325,7 +353,10 @@ const Sidebar = ({
|
||||
return (
|
||||
<div key={key} className="space-y-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<label className="text-sm font-medium text-green-600 break-all">
|
||||
<label
|
||||
className="text-sm font-medium text-green-600 break-all"
|
||||
htmlFor={`${configKey}-input`}
|
||||
>
|
||||
{configItem.label}
|
||||
</label>
|
||||
<Tooltip>
|
||||
@@ -339,6 +370,7 @@ const Sidebar = ({
|
||||
</div>
|
||||
{typeof configItem.value === "number" ? (
|
||||
<Input
|
||||
id={`${configKey}-input`}
|
||||
type="number"
|
||||
data-testid={`${configKey}-input`}
|
||||
value={configItem.value}
|
||||
@@ -365,7 +397,7 @@ const Sidebar = ({
|
||||
setConfig(newConfig);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger id={`${configKey}-input`}>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -375,6 +407,7 @@ const Sidebar = ({
|
||||
</Select>
|
||||
) : (
|
||||
<Input
|
||||
id={`${configKey}-input`}
|
||||
data-testid={`${configKey}-input`}
|
||||
value={configItem.value}
|
||||
onChange={(e) => {
|
||||
@@ -454,14 +487,19 @@ const Sidebar = ({
|
||||
|
||||
{loggingSupported && connectionStatus === "connected" && (
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Logging Level</label>
|
||||
<label
|
||||
className="text-sm font-medium"
|
||||
htmlFor="logging-level-select"
|
||||
>
|
||||
Logging Level
|
||||
</label>
|
||||
<Select
|
||||
value={logLevel}
|
||||
onValueChange={(value: LoggingLevel) =>
|
||||
sendLogLevelRequest(value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger id="logging-level-select">
|
||||
<SelectValue placeholder="Select logging level" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
||||
@@ -69,11 +69,18 @@ const ToolsTab = ({
|
||||
return (
|
||||
<>
|
||||
<h4 className="font-semibold mb-2">
|
||||
Tool Result: {isError ? "Error" : "Success"}
|
||||
Tool Result:{" "}
|
||||
{isError ? (
|
||||
<span className="text-red-600 font-semibold">Error</span>
|
||||
) : (
|
||||
<span className="text-green-600 font-semibold">Success</span>
|
||||
)}
|
||||
</h4>
|
||||
{structuredResult.content.map((item, index) => (
|
||||
<div key={index} className="mb-2">
|
||||
{item.type === "text" && <JsonView data={item.text} />}
|
||||
{item.type === "text" && (
|
||||
<JsonView data={item.text} isError={isError} />
|
||||
)}
|
||||
{item.type === "image" && (
|
||||
<img
|
||||
src={`data:${item.mimeType};base64,${item.data}`}
|
||||
|
||||
Reference in New Issue
Block a user