feat(web): compact two-line HistoryEntry/NetworkEntry for the narrow column (#1616)
In the pinned monitoring column (embedded), the single-line entry headers wrap badly. Add compact two-line variants gated on `embedded`: - HistoryEntry: line 1 = time + client/server badge + elapsed + status; line 2 = method (and target, truncated) on the left with the controls on the right, where Replay becomes an icon (new ReplayButton element) next to Pin/Expand. - NetworkEntry: line 1 = time + HTTP method + category + elapsed + status; line 2 = the URL in a horizontal ScrollArea (new Text `nowrap` variant) with the expand toggle on the right. The full-size (non-embedded) layouts are unchanged. `embedded` is threaded from the History/Network panels into the entries. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bcf10c75dd
commit
3550b64032
3 changed files with 325 additions and 58 deletions
|
|
@ -0,0 +1,19 @@
|
|||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { expect, fn, within } from "storybook/test";
|
||||
import { ReplayButton } from "./ReplayButton";
|
||||
|
||||
const meta: Meta<typeof ReplayButton> = {
|
||||
title: "Elements/ReplayButton",
|
||||
component: ReplayButton,
|
||||
args: { onReplay: fn() },
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof ReplayButton>;
|
||||
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
expect(canvas.getByRole("button", { name: "Replay" })).toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { describe, it, expect, vi } from "vitest";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { renderWithMantine, screen } from "../../../test/renderWithMantine";
|
||||
import { ReplayButton } from "./ReplayButton";
|
||||
|
||||
describe("ReplayButton", () => {
|
||||
it("renders a labelled replay button", () => {
|
||||
renderWithMantine(<ReplayButton onReplay={vi.fn()} />);
|
||||
expect(screen.getByRole("button", { name: "Replay" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("invokes onReplay when clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
const onReplay = vi.fn();
|
||||
renderWithMantine(<ReplayButton onReplay={onReplay} />);
|
||||
await user.click(screen.getByRole("button", { name: "Replay" }));
|
||||
expect(onReplay).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
import { ActionIcon } from "@mantine/core";
|
||||
import { MdReplay } from "react-icons/md";
|
||||
|
||||
export interface ReplayButtonProps {
|
||||
/** Re-send the owning history request. */
|
||||
onReplay: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Icon form of the "Replay" action, used in the compact (column) HistoryEntry
|
||||
* layout where the text button is replaced by a replay icon sitting next to the
|
||||
* pin toggle (#1616). Matches PinToggle's subtle gray icon-button styling.
|
||||
*/
|
||||
export function ReplayButton({ onReplay }: ReplayButtonProps) {
|
||||
return (
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
size="md"
|
||||
aria-label="Replay"
|
||||
onClick={onReplay}
|
||||
>
|
||||
<MdReplay size={18} />
|
||||
</ActionIcon>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue