feat(web): add copyright notice + footer/toolbar polish (#1639)
- Add a grey CopyrightBadge ("Copyright © Model Context Protocol a Series of LF
Projects, LLC.") to the footer. Version (bottom-left) and copyright
(bottom-right) share the bottom `xl` margin band: vertically centered in it
and inset by `xl` to line up with the content's left/right margins.
- Move the list expand/collapse toggle to the right of the "Add Servers" button
in ServerListControls.
- Make the monitoring column's close-sidebar control match the open-sidebar
PinColumnButton theme (Button size sm / variant subtle) instead of a gray
ActionIcon, so the open/close affordances read as a pair.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BrihGWcrM9JGRyu41nzZYw
This commit is contained in:
parent
650e5bd020
commit
5d024ab54f
9 changed files with 88 additions and 18 deletions
|
|
@ -102,6 +102,7 @@ import { useInspectorVersion } from "@inspector/core/react/useInspectorVersion.j
|
|||
import { usePendingClientRequests } from "@inspector/core/react/usePendingClientRequests.js";
|
||||
import { InspectorView } from "./components/views/InspectorView/InspectorView";
|
||||
import { VersionBadge } from "./components/elements/VersionBadge/VersionBadge";
|
||||
import { CopyrightBadge } from "./components/elements/CopyrightBadge/CopyrightBadge";
|
||||
import type {
|
||||
ToolCallState,
|
||||
ToolsUiState,
|
||||
|
|
@ -3824,6 +3825,7 @@ function App() {
|
|||
onRefreshApps={onRefreshTools}
|
||||
/>
|
||||
</Box>
|
||||
<CopyrightBadge />
|
||||
<VersionBadge version={inspectorVersion} />
|
||||
<ServerConfigModal
|
||||
opened={configModal !== null}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { expect, within } from "storybook/test";
|
||||
import { CopyrightBadge, COPYRIGHT_NOTICE } from "./CopyrightBadge";
|
||||
|
||||
const meta: Meta<typeof CopyrightBadge> = {
|
||||
title: "Elements/CopyrightBadge",
|
||||
component: CopyrightBadge,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof CopyrightBadge>;
|
||||
|
||||
// The grey copyright notice pinned to the lower-left corner of the viewport.
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await expect(canvas.getByText(COPYRIGHT_NOTICE)).toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithMantine, screen } from "../../../test/renderWithMantine";
|
||||
import { CopyrightBadge, COPYRIGHT_NOTICE } from "./CopyrightBadge";
|
||||
|
||||
describe("CopyrightBadge", () => {
|
||||
it("renders the project copyright notice", () => {
|
||||
renderWithMantine(<CopyrightBadge />);
|
||||
expect(screen.getByText(COPYRIGHT_NOTICE)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("names the Model Context Protocol and LF Projects", () => {
|
||||
renderWithMantine(<CopyrightBadge />);
|
||||
expect(
|
||||
screen.getByText(/Model Context Protocol.*Series of LF Projects, LLC\./),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { Text } from "@mantine/core";
|
||||
|
||||
/** The project's copyright notice. */
|
||||
export const COPYRIGHT_NOTICE =
|
||||
"Copyright © Model Context Protocol a Series of LF Projects, LLC.";
|
||||
|
||||
// The `copyrightBadge` variant (src/theme/Text.ts) pins it to the lower-right
|
||||
// corner in grey, on the same row as the version badge, and non-interactive.
|
||||
const CopyrightText = Text.withProps({ variant: "copyrightBadge" });
|
||||
|
||||
/**
|
||||
* The project copyright notice, fixed to the lower-right corner of the screen
|
||||
* (#1639) — the grey, non-interactive twin of the lower-left version badge,
|
||||
* sharing its row.
|
||||
*/
|
||||
export function CopyrightBadge() {
|
||||
return <CopyrightText>{COPYRIGHT_NOTICE}</CopyrightText>;
|
||||
}
|
||||
|
|
@ -5,12 +5,12 @@ export interface VersionBadgeProps {
|
|||
version?: string;
|
||||
}
|
||||
|
||||
// The `versionBadge` variant (src/theme/Text.ts) pins it to the lower-right
|
||||
// The `versionBadge` variant (src/theme/Text.ts) pins it to the lower-left
|
||||
// corner in grey and makes it non-interactive.
|
||||
const VersionText = Text.withProps({ variant: "versionBadge" });
|
||||
|
||||
/**
|
||||
* A small, unobtrusive build-version label fixed to the lower-right corner of
|
||||
* A small, unobtrusive build-version label fixed to the lower-left corner of
|
||||
* the screen (#1639). Sourced from the root `package.json` via the backend's
|
||||
* `GET /api/config`; renders nothing until the version is known (or on a legacy
|
||||
* backend that omits it).
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ActionIcon, Group, SegmentedControl, TextInput } from "@mantine/core";
|
||||
import { Button, Group, SegmentedControl, TextInput } from "@mantine/core";
|
||||
import { TbLayoutSidebarRightCollapse } from "react-icons/tb";
|
||||
import { ClearButton } from "../../elements/ClearButton/ClearButton";
|
||||
|
||||
|
|
@ -69,15 +69,14 @@ export function MonitoringControls({
|
|||
) : null
|
||||
}
|
||||
/>
|
||||
<ActionIcon
|
||||
<Button
|
||||
size="sm"
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
size="lg"
|
||||
aria-label="Close monitoring column"
|
||||
onClick={onClose}
|
||||
>
|
||||
<TbLayoutSidebarRightCollapse size={20} />
|
||||
</ActionIcon>
|
||||
</Button>
|
||||
</ControlsBar>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,9 @@ describe("ServerListControls", () => {
|
|||
onToggleList={onToggleList}
|
||||
/>,
|
||||
);
|
||||
const buttons = screen.getAllByRole("button");
|
||||
await user.click(buttons[0]);
|
||||
await user.click(
|
||||
screen.getByRole("button", { name: /Expand all|Collapse all/ }),
|
||||
);
|
||||
expect(onToggleList).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@ export function ServerListControls({
|
|||
}: ServerListControlsProps) {
|
||||
return (
|
||||
<Group justify="flex-end">
|
||||
{serverCount > 0 && (
|
||||
<ListToggle compact={compact} onToggle={onToggleList} />
|
||||
)}
|
||||
<Button variant="default" onClick={onExport} disabled={serverCount === 0}>
|
||||
Export
|
||||
</Button>
|
||||
|
|
@ -40,6 +37,9 @@ export function ServerListControls({
|
|||
onImportServerJson={onImportServerJson}
|
||||
/>
|
||||
)}
|
||||
{serverCount > 0 && (
|
||||
<ListToggle compact={compact} onToggle={onToggleList} />
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,15 +37,29 @@ export const ThemeText = Text.extend({
|
|||
},
|
||||
};
|
||||
}
|
||||
// A small, unobtrusive build-version label pinned to the lower-right corner
|
||||
// of the screen (#1639): grey, non-interactive (clicks pass through), and
|
||||
// out of the tab/selection flow so it never interferes with the UI beneath.
|
||||
if (props.variant === "versionBadge") {
|
||||
// Two small, unobtrusive labels pinned to the bottom corners of the screen
|
||||
// on the same row (#1639): the build version (bottom-left) and the
|
||||
// copyright notice (bottom-right). Each occupies the full-height `xl` bottom
|
||||
// margin band (`height: xl` + flex centering) so the text sits vertically
|
||||
// centered in it, and insets by `xl` horizontally to line up with the
|
||||
// content's left/right margins. Both are grey, non-interactive (clicks pass
|
||||
// through), and out of the tab/selection flow.
|
||||
if (
|
||||
props.variant === "versionBadge" ||
|
||||
props.variant === "copyrightBadge"
|
||||
) {
|
||||
const horizontal =
|
||||
props.variant === "versionBadge"
|
||||
? { left: "var(--mantine-spacing-xl)" }
|
||||
: { right: "var(--mantine-spacing-xl)" };
|
||||
return {
|
||||
root: {
|
||||
position: "fixed",
|
||||
bottom: "0.35rem",
|
||||
right: "0.6rem",
|
||||
bottom: 0,
|
||||
height: "var(--mantine-spacing-xl)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
...horizontal,
|
||||
zIndex: 100,
|
||||
color: "var(--inspector-text-secondary)",
|
||||
fontSize: "var(--mantine-font-size-xs)",
|
||||
|
|
|
|||
Loading…
Reference in a new issue