mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-13 05:58:31 +00:00
Fix: ui
This commit is contained in:
parent
78d401f618
commit
af48e97166
@ -1,8 +1,6 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
List,
|
||||
InfiniteLoader,
|
||||
WindowScroller,
|
||||
AutoSizer,
|
||||
CellMeasurer,
|
||||
CellMeasurerCache,
|
||||
@ -12,21 +10,15 @@ import {
|
||||
import { type LogItem } from "~/hooks/use-logs";
|
||||
import { Badge } from "~/components/ui/badge";
|
||||
import { Card, CardContent } from "~/components/ui/card";
|
||||
import { AlertCircle, ChevronDown, XCircle } from "lucide-react";
|
||||
import { AlertCircle } from "lucide-react";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { ScrollManagedList } from "../virtualized-list";
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogClose,
|
||||
} from "../ui/dialog";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
|
||||
import { Button } from "../ui";
|
||||
|
||||
// --- LogTextCollapse component ---
|
||||
function LogTextCollapse({ text }: { text?: string }) {
|
||||
function LogTextCollapse({ text, error }: { text?: string; error?: string }) {
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
|
||||
// Show collapse if text is long (by word count)
|
||||
@ -52,38 +44,60 @@ function LogTextCollapse({ text }: { text?: string }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mb-2">
|
||||
<p
|
||||
className={cn(
|
||||
"whitespace-p-wrap pt-2 text-sm break-words",
|
||||
isLong ? "max-h-16 overflow-hidden" : "",
|
||||
<>
|
||||
<div className="mb-2">
|
||||
<p
|
||||
className={cn(
|
||||
"whitespace-p-wrap pt-2 text-sm break-words",
|
||||
isLong ? "max-h-16 overflow-hidden" : "",
|
||||
)}
|
||||
style={{ lineHeight: "1.5" }}
|
||||
>
|
||||
{displayText}
|
||||
</p>
|
||||
{isLong && (
|
||||
<>
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<DialogContent className="max-w-2xl p-4">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex w-full items-center justify-between">
|
||||
<span>Log Details</span>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="max-h-[70vh] overflow-auto p-0">
|
||||
<p
|
||||
className="px-3 py-2 text-sm break-words whitespace-pre-wrap"
|
||||
style={{ lineHeight: "1.5" }}
|
||||
>
|
||||
{text}
|
||||
</p>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"text-muted-foreground flex items-center justify-end text-xs",
|
||||
isLong && "justify-between",
|
||||
)}
|
||||
style={{ lineHeight: "1.5" }}
|
||||
>
|
||||
{displayText}
|
||||
</p>
|
||||
{isLong && (
|
||||
<>
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<DialogContent className="max-w-2xl p-4">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex w-full items-center justify-between">
|
||||
<span>Log Details</span>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="max-h-[70vh] overflow-auto p-0">
|
||||
<p
|
||||
className="px-3 py-2 text-sm break-words whitespace-pre-wrap"
|
||||
style={{ lineHeight: "1.5" }}
|
||||
>
|
||||
{text}
|
||||
</p>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{isLong && (
|
||||
<Button variant="ghost" size="sm" className="-ml-2 rounded">
|
||||
See full
|
||||
</Button>
|
||||
)}
|
||||
{error && (
|
||||
<div className="flex items-center gap-1 text-red-600">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
<span className="max-w-[200px] truncate" title={error}>
|
||||
{error}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -169,26 +183,7 @@ function LogItemRenderer(
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LogTextCollapse text={log.ingestText} />
|
||||
|
||||
<div className="text-muted-foreground flex items-center justify-between text-xs">
|
||||
<div className="flex items-center gap-4">
|
||||
{log.processedAt && (
|
||||
<span>
|
||||
Processed: {new Date(log.processedAt).toLocaleString()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{log.error && (
|
||||
<div className="flex items-center gap-1 text-red-600">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
<span className="max-w-[200px] truncate" title={log.error}>
|
||||
{log.error}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<LogTextCollapse text={log.ingestText} error={log.error} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@ -116,33 +116,8 @@ export function createMCPProxy(
|
||||
bridgeOptions
|
||||
);
|
||||
|
||||
// Set up timeout
|
||||
const timeoutId = config.timeout
|
||||
? setTimeout(() => {
|
||||
bridge?.close().catch(console.error);
|
||||
if (!resolve) return;
|
||||
resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
error: "Request timeout",
|
||||
}),
|
||||
{
|
||||
status: 408,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
)
|
||||
);
|
||||
}, config.timeout)
|
||||
: null;
|
||||
|
||||
// Start only the client transport (server is already started)
|
||||
await clientTransport.start();
|
||||
|
||||
// Clean up after a reasonable time (since HTTP is request/response)
|
||||
setTimeout(() => {
|
||||
if (timeoutId) clearTimeout(timeoutId);
|
||||
bridge?.close().catch(console.error);
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
console.error("MCP Transport Proxy Error:", error);
|
||||
|
||||
@ -186,32 +161,16 @@ export function createMCPProxy(
|
||||
// Create transport based on strategy (don't start yet)
|
||||
let transport: SSEClientTransport | StreamableHTTPClientTransport;
|
||||
|
||||
// For SSE, we need eventSourceInit for authentication
|
||||
const eventSourceInit = {
|
||||
fetch: (url: string | URL, init?: RequestInit) => {
|
||||
return fetch(url, {
|
||||
...init,
|
||||
headers: {
|
||||
...(init?.headers as Record<string, string> | undefined),
|
||||
...headers,
|
||||
Accept: "text/event-stream",
|
||||
} as Record<string, string>,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
switch (transportStrategy) {
|
||||
case "sse-only":
|
||||
transport = new SSEClientTransport(url, {
|
||||
authProvider,
|
||||
requestInit: { headers },
|
||||
eventSourceInit,
|
||||
});
|
||||
break;
|
||||
|
||||
case "http-only":
|
||||
transport = new StreamableHTTPClientTransport(url, {
|
||||
authProvider,
|
||||
requestInit: { headers },
|
||||
});
|
||||
break;
|
||||
@ -222,7 +181,6 @@ export function createMCPProxy(
|
||||
transport = new SSEClientTransport(url, {
|
||||
authProvider,
|
||||
requestInit: { headers },
|
||||
eventSourceInit,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn("SSE transport failed, falling back to HTTP:", error);
|
||||
@ -237,7 +195,6 @@ export function createMCPProxy(
|
||||
// Try HTTP first, fallback to SSE on error
|
||||
try {
|
||||
transport = new StreamableHTTPClientTransport(url, {
|
||||
authProvider,
|
||||
requestInit: { headers },
|
||||
});
|
||||
} catch (error) {
|
||||
@ -245,7 +202,6 @@ export function createMCPProxy(
|
||||
transport = new SSEClientTransport(url, {
|
||||
authProvider,
|
||||
requestInit: { headers },
|
||||
eventSourceInit,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
@ -9,8 +9,8 @@ export function createMCPTransportBridge(
|
||||
serverTransport: Transport,
|
||||
options: {
|
||||
debug?: boolean;
|
||||
onMessage?: (direction: 'client-to-server' | 'server-to-client', message: any) => void;
|
||||
onError?: (error: Error, source: 'client' | 'server') => void;
|
||||
onMessage?: (direction: "client-to-server" | "server-to-client", message: any) => void;
|
||||
onError?: (error: Error, source: "client" | "server") => void;
|
||||
} = {}
|
||||
) {
|
||||
let clientClosed = false;
|
||||
@ -23,23 +23,25 @@ export function createMCPTransportBridge(
|
||||
|
||||
// Forward messages from client to server
|
||||
clientTransport.onmessage = (message: any) => {
|
||||
log('[Client→Server]', message.method || message.id);
|
||||
onMessage?.('client-to-server', message);
|
||||
|
||||
serverTransport.send(message).catch(error => {
|
||||
logError('Error sending to server:', error);
|
||||
onError?.(error, 'server');
|
||||
console.log(JSON.stringify(message));
|
||||
log("[Client→Server]", message.method || message.id);
|
||||
onMessage?.("client-to-server", message);
|
||||
|
||||
serverTransport.send(message).catch((error) => {
|
||||
logError("Error sending to server:", error);
|
||||
onError?.(error, "server");
|
||||
});
|
||||
};
|
||||
|
||||
// Forward messages from server to client
|
||||
serverTransport.onmessage = (message: any) => {
|
||||
log('[Server→Client]', message.method || message.id);
|
||||
onMessage?.('server-to-client', message);
|
||||
|
||||
clientTransport.send(message).catch(error => {
|
||||
logError('Error sending to client:', error);
|
||||
onError?.(error, 'client');
|
||||
console.log(JSON.stringify(message));
|
||||
log("[Server→Client]", message.method || message.id);
|
||||
onMessage?.("server-to-client", message);
|
||||
|
||||
clientTransport.send(message).catch((error) => {
|
||||
logError("Error sending to client:", error);
|
||||
onError?.(error, "client");
|
||||
});
|
||||
};
|
||||
|
||||
@ -47,30 +49,30 @@ export function createMCPTransportBridge(
|
||||
clientTransport.onclose = () => {
|
||||
if (serverClosed) return;
|
||||
clientClosed = true;
|
||||
log('Client transport closed, closing server transport');
|
||||
serverTransport.close().catch(error => {
|
||||
logError('Error closing server transport:', error);
|
||||
log("Client transport closed, closing server transport");
|
||||
serverTransport.close().catch((error) => {
|
||||
logError("Error closing server transport:", error);
|
||||
});
|
||||
};
|
||||
|
||||
serverTransport.onclose = () => {
|
||||
if (clientClosed) return;
|
||||
serverClosed = true;
|
||||
log('Server transport closed, closing client transport');
|
||||
clientTransport.close().catch(error => {
|
||||
logError('Error closing client transport:', error);
|
||||
log("Server transport closed, closing client transport");
|
||||
clientTransport.close().catch((error) => {
|
||||
logError("Error closing client transport:", error);
|
||||
});
|
||||
};
|
||||
|
||||
// Error handling
|
||||
clientTransport.onerror = (error: Error) => {
|
||||
logError('Client transport error:', error);
|
||||
onError?.(error, 'client');
|
||||
logError("Client transport error:", error);
|
||||
onError?.(error, "client");
|
||||
};
|
||||
|
||||
serverTransport.onerror = (error: Error) => {
|
||||
logError('Server transport error:', error);
|
||||
onError?.(error, 'server');
|
||||
logError("Server transport error:", error);
|
||||
onError?.(error, "server");
|
||||
};
|
||||
|
||||
return {
|
||||
@ -79,13 +81,10 @@ export function createMCPTransportBridge(
|
||||
*/
|
||||
start: async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
clientTransport.start(),
|
||||
serverTransport.start()
|
||||
]);
|
||||
log('MCP transport bridge started successfully');
|
||||
await Promise.all([clientTransport.start(), serverTransport.start()]);
|
||||
log("MCP transport bridge started successfully");
|
||||
} catch (error) {
|
||||
logError('Error starting transport bridge:', error);
|
||||
logError("Error starting transport bridge:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
@ -95,13 +94,10 @@ export function createMCPTransportBridge(
|
||||
*/
|
||||
close: async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
clientTransport.close(),
|
||||
serverTransport.close()
|
||||
]);
|
||||
log('MCP transport bridge closed successfully');
|
||||
await Promise.all([clientTransport.close(), serverTransport.close()]);
|
||||
log("MCP transport bridge closed successfully");
|
||||
} catch (error) {
|
||||
logError('Error closing transport bridge:', error);
|
||||
logError("Error closing transport bridge:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
@ -111,6 +107,6 @@ export function createMCPTransportBridge(
|
||||
*/
|
||||
get isClosed() {
|
||||
return clientClosed || serverClosed;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,5 +83,7 @@ export class RemixMCPTransport implements Transport {
|
||||
|
||||
onmessage: (message: any) => void = () => {};
|
||||
onclose: () => void = () => {};
|
||||
onerror: (error: Error) => void = () => {};
|
||||
async onerror(error: Error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user