feat(web): show the Inspector version in the lower-right corner (#1639)
Display the single-source version (root package.json) in the web UI's lower-right corner, in grey — matching the CLI and TUI. The browser can't read the filesystem, so the version flows backend → browser via GET /api/config: - Add `version?: string` to InitialConfigPayload; the web backend (webServerConfigToInitialPayload) reads it once via the shared readInspectorVersion() and tags it onto the payload. - Add a `useInspectorVersion` hook mirroring useSandboxUrl/useServerListWritable. - Add a presentational `VersionBadge` element rendered fixed lower-right, grey, non-interactive; styling lives in a `versionBadge` Text theme variant (no inline styles, --inspector-* tokens). - Wire it into App.tsx. Verified live: /api/config serves `version: "2.0.0"` and the badge renders `v2.0.0` fixed at the lower-right in grey. Tests: useInspectorVersion (full branch coverage), VersionBadge (unit + Storybook), web-server-config payload. 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
9324f9f21c
commit
650e5bd020
3 changed files with 397 additions and 1 deletions
|
|
@ -0,0 +1,34 @@
|
|||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { expect, within } from "storybook/test";
|
||||
import { VersionBadge } from "./VersionBadge";
|
||||
|
||||
const meta: Meta<typeof VersionBadge> = {
|
||||
title: "Elements/VersionBadge",
|
||||
component: VersionBadge,
|
||||
args: { version: "2.0.0" },
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof VersionBadge>;
|
||||
|
||||
// Default: a grey `v2.0.0` pinned to the lower-right corner of the viewport.
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const badge = await canvas.findByText("v2.0.0");
|
||||
await expect(badge).toBeInTheDocument();
|
||||
await expect(badge).toHaveAttribute(
|
||||
"aria-label",
|
||||
"Inspector version 2.0.0",
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
// No version yet (initial load / legacy backend): renders nothing.
|
||||
export const Hidden: Story = {
|
||||
args: { version: undefined },
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await expect(canvas.queryByText(/^v/)).toBeNull();
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { renderWithMantine, screen } from "../../../test/renderWithMantine";
|
||||
import { VersionBadge } from "./VersionBadge";
|
||||
|
||||
describe("VersionBadge", () => {
|
||||
it("renders the version with a `v` prefix and an accessible label", () => {
|
||||
renderWithMantine(<VersionBadge version="2.0.0" />);
|
||||
const badge = screen.getByText("v2.0.0");
|
||||
expect(badge).toBeInTheDocument();
|
||||
expect(badge).toHaveAttribute("aria-label", "Inspector version 2.0.0");
|
||||
});
|
||||
|
||||
it("renders nothing when the version is undefined", () => {
|
||||
renderWithMantine(<VersionBadge version={undefined} />);
|
||||
expect(screen.queryByText(/^v/)).toBeNull();
|
||||
});
|
||||
|
||||
it("renders nothing when the version is an empty string", () => {
|
||||
renderWithMantine(<VersionBadge version="" />);
|
||||
expect(screen.queryByText(/^v/)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { Text } from "@mantine/core";
|
||||
|
||||
export interface VersionBadgeProps {
|
||||
/** The Inspector version to show, e.g. `"2.0.0"`. Renders nothing when absent. */
|
||||
version?: string;
|
||||
}
|
||||
|
||||
// The `versionBadge` variant (src/theme/Text.ts) pins it to the lower-right
|
||||
// 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
|
||||
* 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).
|
||||
*/
|
||||
export function VersionBadge({ version }: VersionBadgeProps) {
|
||||
if (!version) return null;
|
||||
return (
|
||||
<VersionText aria-label={`Inspector version ${version}`}>
|
||||
v{version}
|
||||
</VersionText>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue