Animate InspectorView screen transitions and refactor App.tsx
- InspectorView: wrap each screen in a Mantine `Transition` (`fade-up`, 350ms). Outgoing screens fade out and slide down 30px; incoming screens fade in and slide up to meet the ViewHeader. A `pos: "relative"` Stack container holds the screens so the absolute-positioned `Transition` wrappers stack in the same area without pushing layout. - InspectorView: reorder ALL_TABS so Logs sits beside History at the end: Servers · Tools · Prompts · Resources · Tasks · Logs · History. - App.tsx: refactor to AGENTS.md guidelines — extract `PageContainer`, `PageStack`, `ThemeToggle`, `SubtitleText` as `.withProps()` subcomponents; replace inline unicode glyphs with `MdLightMode` / `MdDarkMode` icons (matches the ViewHeader pattern); convert the click handler to a `function` declaration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
473bd95826
commit
d3c2645e38
2 changed files with 157 additions and 103 deletions
|
|
@ -1,41 +1,59 @@
|
|||
import {
|
||||
Title,
|
||||
Text,
|
||||
Container,
|
||||
Stack,
|
||||
useMantineColorScheme,
|
||||
useComputedColorScheme,
|
||||
ActionIcon,
|
||||
Container,
|
||||
Group,
|
||||
Stack,
|
||||
Text,
|
||||
Title,
|
||||
useComputedColorScheme,
|
||||
useMantineColorScheme,
|
||||
} from "@mantine/core";
|
||||
import { MdDarkMode, MdLightMode } from "react-icons/md";
|
||||
|
||||
const PageContainer = Container.withProps({
|
||||
size: "sm",
|
||||
py: "xl",
|
||||
});
|
||||
|
||||
const PageStack = Stack.withProps({
|
||||
align: "center",
|
||||
gap: "md",
|
||||
});
|
||||
|
||||
const ThemeToggle = ActionIcon.withProps({
|
||||
variant: "default",
|
||||
size: "lg",
|
||||
"aria-label": "Toggle color scheme",
|
||||
});
|
||||
|
||||
const SubtitleText = Text.withProps({
|
||||
c: "var(--inspector-text-secondary)",
|
||||
});
|
||||
|
||||
function App() {
|
||||
const { setColorScheme } = useMantineColorScheme();
|
||||
const computedColorScheme = useComputedColorScheme("light");
|
||||
const isDark = computedColorScheme === "dark";
|
||||
const ThemeIcon = isDark ? MdLightMode : MdDarkMode;
|
||||
|
||||
const toggleColorScheme = () => {
|
||||
setColorScheme(computedColorScheme === "dark" ? "light" : "dark");
|
||||
};
|
||||
function toggleColorScheme() {
|
||||
setColorScheme(isDark ? "light" : "dark");
|
||||
}
|
||||
|
||||
return (
|
||||
<Container size="sm" py="xl">
|
||||
<Stack align="center" gap="md">
|
||||
<PageContainer>
|
||||
<PageStack>
|
||||
<Group>
|
||||
<Title order={1}>MCP Inspector</Title>
|
||||
<ActionIcon
|
||||
onClick={toggleColorScheme}
|
||||
variant="default"
|
||||
size="lg"
|
||||
aria-label="Toggle color scheme"
|
||||
>
|
||||
{computedColorScheme === "dark" ? "\u2600" : "\u263E"}
|
||||
</ActionIcon>
|
||||
<ThemeToggle onClick={toggleColorScheme}>
|
||||
<ThemeIcon size={20} />
|
||||
</ThemeToggle>
|
||||
</Group>
|
||||
<Text c="var(--inspector-text-secondary)">
|
||||
<SubtitleText>
|
||||
Web client for the Model Context Protocol Inspector
|
||||
</Text>
|
||||
</Stack>
|
||||
</Container>
|
||||
</SubtitleText>
|
||||
</PageStack>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useMemo, useState } from "react";
|
||||
import { AppShell } from "@mantine/core";
|
||||
import { useMemo, useState, type ReactNode } from "react";
|
||||
import { AppShell, Box, Stack, Transition } from "@mantine/core";
|
||||
import type {
|
||||
InitializeResult,
|
||||
LoggingLevel,
|
||||
|
|
@ -35,11 +35,45 @@ const ALL_TABS: string[] = [
|
|||
"Tools",
|
||||
"Prompts",
|
||||
"Resources",
|
||||
"Logs",
|
||||
"Tasks",
|
||||
"Logs",
|
||||
"History",
|
||||
];
|
||||
|
||||
const SCREEN_TRANSITION_MS = 350;
|
||||
|
||||
const ScreenStageContainer = Stack.withProps({
|
||||
pos: "relative",
|
||||
gap: 0,
|
||||
flex: 1,
|
||||
mih: "100%",
|
||||
});
|
||||
|
||||
function ScreenStage({
|
||||
active,
|
||||
children,
|
||||
}: {
|
||||
active: boolean;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<Transition
|
||||
mounted={active}
|
||||
transition="fade-up"
|
||||
duration={SCREEN_TRANSITION_MS}
|
||||
timingFunction="ease"
|
||||
>
|
||||
{(styles) => (
|
||||
// `style={styles}` is the runtime transition state from Mantine's
|
||||
// Transition API — these are interpolated values, not static styling.
|
||||
<Box style={styles} pos="absolute" top={0} left={0} right={0}>
|
||||
{children}
|
||||
</Box>
|
||||
)}
|
||||
</Transition>
|
||||
);
|
||||
}
|
||||
|
||||
// Demo stub: every screen-action callback below resolves to noop. Phase 3
|
||||
// wiring will replace each with its real `useManaged*` / `useConnection`
|
||||
// hook call. Anything still pointing here in Phase 3 is unfinished.
|
||||
|
|
@ -204,84 +238,86 @@ export function InspectorView({
|
|||
)}
|
||||
</AppShell.Header>
|
||||
<AppShell.Main>
|
||||
{activeTab === SERVERS_TAB && (
|
||||
<ServerListScreen
|
||||
servers={servers}
|
||||
activeServer={activeServer}
|
||||
onAddManually={noop}
|
||||
onImportConfig={noop}
|
||||
onImportServerJson={noop}
|
||||
onToggleConnection={handleToggleConnection}
|
||||
onServerInfo={noop}
|
||||
onSettings={noop}
|
||||
onEdit={noop}
|
||||
onClone={noop}
|
||||
onRemove={noop}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "Tools" && (
|
||||
<ToolsScreen
|
||||
tools={tools}
|
||||
listChanged={false}
|
||||
onRefreshList={noop}
|
||||
onSelectTool={noop}
|
||||
onCallTool={noop}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "Prompts" && (
|
||||
<PromptsScreen
|
||||
prompts={prompts}
|
||||
listChanged={false}
|
||||
onRefreshList={noop}
|
||||
onSelectPrompt={noop}
|
||||
onGetPrompt={noop}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "Resources" && (
|
||||
<ResourcesScreen
|
||||
resources={resources}
|
||||
templates={resourceTemplates}
|
||||
subscriptions={subscriptions}
|
||||
listChanged={false}
|
||||
onRefreshList={noop}
|
||||
onSelectUri={noop}
|
||||
onSelectTemplate={noop}
|
||||
onReadResource={noop}
|
||||
onSubscribeResource={noop}
|
||||
onUnsubscribeResource={noop}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "Logs" && (
|
||||
<LoggingScreen
|
||||
entries={logs}
|
||||
currentLevel={logLevel}
|
||||
onSetLevel={setLogLevel}
|
||||
onClear={noop}
|
||||
onExport={noop}
|
||||
autoScroll={autoScroll}
|
||||
onToggleAutoScroll={() => setAutoScroll((prev) => !prev)}
|
||||
onCopyAll={noop}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "Tasks" && (
|
||||
<TasksScreen
|
||||
tasks={tasks}
|
||||
progressByTaskId={progressByTaskId}
|
||||
onRefresh={noop}
|
||||
onClearCompleted={noop}
|
||||
onCancel={noop}
|
||||
/>
|
||||
)}
|
||||
{activeTab === "History" && (
|
||||
<HistoryScreen
|
||||
entries={history}
|
||||
pinnedIds={new Set()}
|
||||
onClearAll={noop}
|
||||
onExport={noop}
|
||||
onReplay={noop}
|
||||
onTogglePin={noop}
|
||||
/>
|
||||
)}
|
||||
<ScreenStageContainer>
|
||||
<ScreenStage active={activeTab === SERVERS_TAB}>
|
||||
<ServerListScreen
|
||||
servers={servers}
|
||||
activeServer={activeServer}
|
||||
onAddManually={noop}
|
||||
onImportConfig={noop}
|
||||
onImportServerJson={noop}
|
||||
onToggleConnection={handleToggleConnection}
|
||||
onServerInfo={noop}
|
||||
onSettings={noop}
|
||||
onEdit={noop}
|
||||
onClone={noop}
|
||||
onRemove={noop}
|
||||
/>
|
||||
</ScreenStage>
|
||||
<ScreenStage active={activeTab === "Tools"}>
|
||||
<ToolsScreen
|
||||
tools={tools}
|
||||
listChanged={false}
|
||||
onRefreshList={noop}
|
||||
onSelectTool={noop}
|
||||
onCallTool={noop}
|
||||
/>
|
||||
</ScreenStage>
|
||||
<ScreenStage active={activeTab === "Prompts"}>
|
||||
<PromptsScreen
|
||||
prompts={prompts}
|
||||
listChanged={false}
|
||||
onRefreshList={noop}
|
||||
onSelectPrompt={noop}
|
||||
onGetPrompt={noop}
|
||||
/>
|
||||
</ScreenStage>
|
||||
<ScreenStage active={activeTab === "Resources"}>
|
||||
<ResourcesScreen
|
||||
resources={resources}
|
||||
templates={resourceTemplates}
|
||||
subscriptions={subscriptions}
|
||||
listChanged={false}
|
||||
onRefreshList={noop}
|
||||
onSelectUri={noop}
|
||||
onSelectTemplate={noop}
|
||||
onReadResource={noop}
|
||||
onSubscribeResource={noop}
|
||||
onUnsubscribeResource={noop}
|
||||
/>
|
||||
</ScreenStage>
|
||||
<ScreenStage active={activeTab === "Tasks"}>
|
||||
<TasksScreen
|
||||
tasks={tasks}
|
||||
progressByTaskId={progressByTaskId}
|
||||
onRefresh={noop}
|
||||
onClearCompleted={noop}
|
||||
onCancel={noop}
|
||||
/>
|
||||
</ScreenStage>
|
||||
<ScreenStage active={activeTab === "Logs"}>
|
||||
<LoggingScreen
|
||||
entries={logs}
|
||||
currentLevel={logLevel}
|
||||
onSetLevel={setLogLevel}
|
||||
onClear={noop}
|
||||
onExport={noop}
|
||||
autoScroll={autoScroll}
|
||||
onToggleAutoScroll={() => setAutoScroll((prev) => !prev)}
|
||||
onCopyAll={noop}
|
||||
/>
|
||||
</ScreenStage>
|
||||
<ScreenStage active={activeTab === "History"}>
|
||||
<HistoryScreen
|
||||
entries={history}
|
||||
pinnedIds={new Set()}
|
||||
onClearAll={noop}
|
||||
onExport={noop}
|
||||
onReplay={noop}
|
||||
onTogglePin={noop}
|
||||
/>
|
||||
</ScreenStage>
|
||||
</ScreenStageContainer>
|
||||
</AppShell.Main>
|
||||
</AppShell>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue