Skip to content

Modernize mitmweb tabs and footer - #8362

Open
lups2000 wants to merge 4 commits into
mitmproxy:mainfrom
lups2000:web-improve
Open

Modernize mitmweb tabs and footer#8362
lups2000 wants to merge 4 commits into
mitmproxy:mainfrom
lups2000:web-improve

Conversation

@lups2000

@lups2000 lups2000 commented Aug 5, 2026

Copy link
Copy Markdown
Member

Description

This PR slightly updates the mitmweb interface without changing its overall structure:

  1. Adds subtle rounded corners and clearer hover states to the main tabs.
  2. Reuses the existing Badge component, introduced in mitmweb: add status/method badges to the flow table #8335, for footer status indicators.
  3. Improves footer spacing, wrapping, and colors in dark mode.
Screenshot 2026-08-05 at 10 34 00 Screenshot 2026-08-05 at 10 34 19

Checklist

  • I have updated tests where applicable.
  • I have added an entry to the CHANGELOG.

@lups2000
lups2000 requested a review from sleeyax August 5, 2026 08:39

@sleeyax sleeyax left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

Comment thread web/src/css/tabs.less
Comment on lines +52 to +54
&.active {
background-color: var(--mitmweb-bg);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This style is obsolete because this exact background-color is already applied at https://github.com/lups2000/mitmproxy/blob/450190c650745923a42768a8a35a68059e063d3e/web/src/css/tabs.less#L21

So you can simply remove this.

Comment thread web/src/css/tabs.less
Comment on lines +46 to +47
&:not(.active):not(.special):hover,
&:not(.active):not(.special):focus {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

These tabs are <a href="#">, so they hang onto focus after you click them and the hover background sticks around even once the mouse has moved away. :focus-visible would keep the highlight for keyboard users without that side effect.

&.special:focus a few lines down has the same issue. It leaves the File button looking permanently pressed.

type BadgeProps = {
className?: string;
children: React.ReactNode;
title?: string;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be easier to just spread the span props here:

type BadgeProps = React.ComponentPropsWithoutRef<"span">;

export default function Badge({ className, children, ...props }: BadgeProps) {
    return (
        <span className={classnames("badge", className)} {...props}>
            {children}
        </span>
    );
}

Somewhat related: className="footer-badge footer-badge-success" is duplicated 11 times in Footer.tsx, and a typo in one of those would work fine but render an unstyled pill. A typed variant prop could catch that. But perhaps this is out of scope for this PR, up to you.

Comment thread web/src/css/badges.less
color: var(--mitmweb-fg-muted);
}

.footer-badge {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that these replace them, the old .label* classes don't have any consumers anymore. The Footer.tsx component was the only one. Might as well delete them while you're in here: https://github.com/lups2000/mitmproxy/blob/450190c650745923a42768a8a35a68059e063d3e/web/src/css/global.less#L469-L499

The .eventlog .label class look unused too, but that one's been dead for a while, so no need to drag it into this PR unless you feel like it.

Comment on lines +33 to +50
[
"regular,upstream:https://example.com",
"Intercept: ~q",
"ssl_insecure",
"showhost",
"no-upstream-cert",
"no-raw-tcp",
"no-http2",
"no-websocket",
"anticache",
"anticomp",
"stickyauth: ~u example.com",
"stickycookie: ~d example.com",
"stream: 1mb",
"1 of 5 flows selected",
"127.0.0.1:9090",
"mitmproxy 1.2.3",
].forEach((text) => expect(screen.getByText(text)).toBeVisible());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not mistaken jsdom doesn't load the stylesheet, so toBeVisible() is basically just toBeInTheDocument() here. The test checks that the labels render but not that they got the right colors, so if someone swapped every variant around this would still pass.

Probably worth asserting a few of them directly:

expect(screen.getByText("ssl_insecure")).toHaveClass("footer-badge-danger");
expect(screen.getByText("anticache")).toHaveClass("footer-badge-success");
expect(screen.getByText("127.0.0.1:9090")).toHaveClass("footer-badge-info");

Also, every option in the fixture is set to whichever value renders a badge, so the other branch never gets exercised. One more test with http2: true checking that screen.queryByText("no-http2") is null would cover it.

import { TStore } from "../ducks/tutils";

test("renders active options as badges", () => {
const state = TStore().getState();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

You could import testState from ../ducks/tutils directly and skip the round-trip through a throwaway store:

const store = TStore({
    ...testState,
    options: { ...testState.options, /* ... */ },
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants