inspector/clients/tui/src/components/NotificationsTab.tsx

83 lines
2.4 KiB
TypeScript

import React, { useEffect, useRef } from "react";
import { Box, Text, useInput, type Key } from "ink";
import { ScrollView, type ScrollViewRef } from "ink-scroll-view";
import type { StderrLogEntry } from "@inspector/core/mcp/index.js";
interface NotificationsTabProps {
stderrLogs: StderrLogEntry[];
width: number;
height: number;
onCountChange?: (count: number) => void;
focused?: boolean;
}
export function NotificationsTab({
stderrLogs,
width,
height,
onCountChange,
focused = false,
}: NotificationsTabProps) {
const scrollViewRef = useRef<ScrollViewRef>(null);
const onCountChangeRef = useRef(onCountChange);
// Update ref when callback changes
useEffect(() => {
onCountChangeRef.current = onCountChange;
}, [onCountChange]);
useEffect(() => {
onCountChangeRef.current?.(stderrLogs.length);
}, [stderrLogs.length]);
// Handle keyboard input for scrolling
useInput(
(input: string, key: Key) => {
if (focused) {
if (key.upArrow) {
scrollViewRef.current?.scrollBy(-1);
} else if (key.downArrow) {
scrollViewRef.current?.scrollBy(1);
} else if (key.pageUp) {
const viewportHeight =
scrollViewRef.current?.getViewportHeight() || 1;
scrollViewRef.current?.scrollBy(-viewportHeight);
} else if (key.pageDown) {
const viewportHeight =
scrollViewRef.current?.getViewportHeight() || 1;
scrollViewRef.current?.scrollBy(viewportHeight);
}
}
},
{ isActive: focused },
);
return (
<Box width={width} height={height} flexDirection="column" paddingX={1}>
<Box paddingY={1} flexShrink={0}>
<Text bold backgroundColor={focused ? "yellow" : undefined}>
Console ({stderrLogs.length})
</Text>
</Box>
{stderrLogs.length === 0 ? (
<Box paddingY={1}>
<Text dimColor>No stderr output yet</Text>
</Box>
) : (
<ScrollView ref={scrollViewRef} height={height - 3}>
{stderrLogs.map((log, index) => (
<Box
key={`log-${log.timestamp.getTime()}-${index}`}
paddingY={0}
flexDirection="row"
flexShrink={0}
>
<Text dimColor>[{log.timestamp.toLocaleTimeString()}] </Text>
<Text color="red">{log.message}</Text>
</Box>
))}
</ScrollView>
)}
</Box>
);
}