inspector/clients/web/src/components/groups/LogControls/LogControls.tsx
cliffhall 95e3a2dca7 Phase 2: Refactor Logs cluster to MCP SDK types
Replace string-typed log levels with SDK LoggingLevel across the Logs
group components and LoggingScreen.

- LogControls: type currentLevel, visibleLevels, and all handlers with
  LoggingLevel instead of string; type LOG_LEVELS array and LEVEL_COLORS
  record with LoggingLevel
- LogStreamPanel: type visibleLevels as Record<LoggingLevel, boolean>
  instead of Record<string, boolean>
- LoggingScreen: type currentLevel, onSetLevel, visibleLevels state,
  and toggle handlers with LoggingLevel; extract NO_LEVELS_VISIBLE as
  a module-level constant
- Stories already used LoggingLevel literals; updated type annotations
  to use Record<LoggingLevel, boolean>
- No ConnectedView story changes needed (already passes valid
  LoggingLevel values)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 19:39:19 -04:00

114 lines
2.7 KiB
TypeScript

import {
Button,
Group,
Select,
Stack,
Text,
TextInput,
Title,
UnstyledButton,
} from "@mantine/core";
import type { LoggingLevel } from "@modelcontextprotocol/sdk/types.js";
const LOG_LEVELS: LoggingLevel[] = [
"debug",
"info",
"notice",
"warning",
"error",
"critical",
"alert",
"emergency",
];
const LEVEL_COLORS: Record<LoggingLevel, { c: string }> = {
debug: { c: "dimmed" },
info: { c: "blue" },
notice: { c: "teal" },
warning: { c: "yellow" },
error: { c: "red" },
critical: { c: "red" },
alert: { c: "red" },
emergency: { c: "red" },
};
const SubtleButton = Button.withProps({
variant: "subtle",
size: "xs",
});
export interface LogControlsProps {
currentLevel: LoggingLevel;
filterText: string;
visibleLevels: Record<LoggingLevel, boolean>;
onSetLevel: (level: LoggingLevel) => void;
onFilterChange: (text: string) => void;
onToggleLevel: (level: LoggingLevel, visible: boolean) => void;
onToggleAllLevels: () => void;
}
export function LogControls({
currentLevel,
filterText,
visibleLevels,
onSetLevel,
onFilterChange,
onToggleLevel,
onToggleAllLevels,
}: LogControlsProps) {
return (
<Stack gap="md">
<Title order={4}>Logging</Title>
<TextInput
placeholder="Search..."
value={filterText}
onChange={(e) => onFilterChange(e.currentTarget.value)}
/>
<Title order={5}>Set Active Level</Title>
<Group wrap="nowrap">
<Select
flex={1}
data={LOG_LEVELS.map((level) => ({ value: level, label: level }))}
value={currentLevel}
onChange={(value) => {
if (value) onSetLevel(value as LoggingLevel);
}}
/>
<Button size="sm" onClick={() => onSetLevel(currentLevel)}>
Set
</Button>
</Group>
<Group justify="space-between">
<Title order={5}>Filter by Level</Title>
<SubtleButton onClick={onToggleAllLevels}>
{Object.values(visibleLevels).every(Boolean)
? "Deselect All"
: "Select All"}
</SubtleButton>
</Group>
<Stack gap="xs">
{LOG_LEVELS.map((level) => {
const style = LEVEL_COLORS[level];
const active = visibleLevels[level];
return (
<UnstyledButton
key={level}
w="100%"
p="sm"
variant="listItem"
bg={active ? "var(--mantine-primary-color-light)" : undefined}
onClick={() => onToggleLevel(level, !active)}
>
<Text c={style.c} ta="center" fw={500}>
{level}
</Text>
</UnstyledButton>
);
})}
</Stack>
</Stack>
);
}