Skip to content

Fix Network toolbar and footer overflow on narrow screens - #10057

Open
NemesisDevX wants to merge 2 commits into
flutter:masterfrom
NemesisDevX:contrib/network-responsive-10004-owner
Open

NemesisDevX wants to merge 2 commits into
flutter:masterfrom
NemesisDevX:contrib/network-responsive-10004-owner

Conversation

@NemesisDevX

@NemesisDevX NemesisDevX commented Oct 28, 2026 •

Copy link
Copy Markdown

Fixes #10004

The Network screen toolbar and the shared footer status line overflowed and overlapped at narrow widths (328 to 599 px). The toolbar's search and filter fields were squeezed into one row beside fixed controls. The footer's page status, device text and embedded actions did not fit.

What changes

  • Network toolbar: below 600 px the search field gets its own row. Below 900 px the filter field gets its own row. At 900 px and above the layout is unchanged.
  • Footer (StatusLine, shared by all screens): footer text is truncated with an ellipsis instead of overflowing. Below 900 px the video tutorial link and, when DevTools is embedded, the Settings, Feedback, About and extension-settings actions move into a "More actions" popup. Each item calls the same callback as its inline control, and the tutorial item records the same analytics event. Below 600 px the disconnected status shows an icon with a tooltip instead of text.
  • DevToolsScaffold.defaultActions now returns List<ScaffoldAction> (was List<Widget>), so the footer can reuse the existing actions. The other caller in app.dart is unchanged.
  • Release note added under "Network profiler updates".

Reviewer notes:

  • At 328 px in standalone mode the popup contains only the tutorial. Settings, Feedback and About stay in the top bar, as before.
  • The "More actions" trigger renders 48 × 27 logical px, the height of the footer. It is not a 48 px square target.

Before and after

Before and after captures at 328 px and 411 px, and separate 1400 px desktop comparisons, were taken with headless Chromium against the upstream base (9ac04e2) and this branch, using the same networking test app. They are attached below as public GitHub attachments.

Attachments, all public GitHub user attachments. The GIF and images were captured by scripts that drove headless Chromium against real pages. This is agent-operated capture, not manual testing.

Corrected 9.8-second GIF. Three scenes: 328 px standalone, 411 px embedded footer, and the More actions menu open at 411 px. Each frame shows the upstream base on the left and this branch on the right.

Narrow-screen before and after GIF, base left and this branch right

328 px standalone. Base on the left, this branch on the right.

328 px standalone before and after, base left and this branch right

411 px embedded footer. Base on the left, this branch on the right.

411 px embedded footer before and after, base left and this branch right

411 px embedded, More actions menu open. The popup overlaps part of the footer while it is open.

411 px More actions menu open, base left and this branch right

1400 px desktop, standalone. Base on top, this branch below. The top toolbar band and the request details pane are pixel-identical between builds. The footer request count differs with traffic.

1400 px desktop standalone, base top and this branch bottom

1400 px desktop, embedded. Base on top, this branch below.

1400 px desktop embedded, base top and this branch bottom

Tests

Run on the repository-pinned candidate SDK (Flutter 3.50.0-0.2.pre, revision fab991537bf). Results below are split by commit because the test selection changed when the review follow-up added tests.

Initial commit 3d3804d:

Check Result
flutter test on status_line_test.dart and network_responsive_test.dart 71 of 71 passed
flutter test on framework, network, logging, extension, memory diff and property editor suites 338 of 338 passed
dart format --set-exit-if-changed (changed files) 0 changed
dart analyze (changed files) and dart analyze lib No issues
dt presubmit (without --fix) Passed with exit 0. Warnings: nonfatal analytics network exceptions, and flutter_lints resolution warnings in fixture format checks.

Review follow-up commit 416fe20 (addresses the two review comments: Flexible page status, stable keys for the search/filter fields):

Check Result
flutter test on status_line_test.dart and network_responsive_test.dart 78 of 78 passed, including the new resize state-preservation and page-status-width tests
flutter test on test/framework, test/screens/network and test/screens/logging 299 of 299 passed (a different selection than the earlier 338-test run, not a regression)
dart analyze (changed files) No issues
dt presubmit (without --fix) Passed with exit 0, covering dart analyze --fatal-infos and dart format --set-exit-if-changed across the repo. Warnings: nonfatal analytics network exceptions, and flutter_lints resolution warnings in fixture format checks.
flutter test test/ (full devtools_app suite, last run on 3d3804d; not rerun for 416fe20, which only touches the footer and toolbar covered above) Not clean locally. Candidate runs ended with 1 unrecovered failure each (+1721 ~12 -1, and +1720 ~12 -1 with exit 1). The base 9ac04e2 run also failed (+1649 ~12 -1). The failures are a CPU-profile benchmark threshold (GenerateFromCpuSamplesBenchmark, expected under 120000) and an intermittent "used after being disposed" error on ValueNotifier<StackFrameAndSourcePosition?>. Both also occur on the base. This change does not touch those tests, and I did not alter them. CI is the reference for the full suite.

Not run: golden tests, integration_test/ tests, and macOS or Windows desktop builds.

Known limitations (pre-existing, not changed here)

  • Keyboard: Tab from the page does not reach the footer, because the screen body is a Flutter focus scope. This is the same on the upstream base. Once the More actions trigger has focus, Enter or Space opens the menu, Tab and Shift+Tab move between items, Enter activates an item, and Escape closes the menu. In Chromium, arrow keys do not move focus within the popup. Flutter's stock PopupMenuButton behaves the same on this SDK. The widget tests cover arrow keys under the Flutter test binding, not in a browser.
  • Settings dialog: its checkbox rows overflow below 600 px, in shared dialog code that also overflows on the base. The Settings menu item is tested at 600 px only.
  • Page status: "Showing N of M requests" is hidden below 600 px, as on the base.
  • Screen readers were not tested.
  • The browser checks were scripted (Playwright driving headless Chromium, profile-mode web builds, Windows). They are not manual testing.

AI assistance disclosure

Implementation and tests were developed with AI assistance (Devin, an AI software agent), which also ran the scripted browser checks. GPT-6, an AI model, reviewed the change and the evidence. The contributor directed and supervised this work, has reviewed the submitted changes, understands them, and takes responsibility for them. An earlier series of agent-authored development commits is not part of this PR. This PR contains a single commit with the same tree as the tested branch.

Checklist

Pre-launch checklist (boxes left unchecked are for the contributor to confirm personally):

General checklist:

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read the Flutter Style Guide recently, and have followed its advice.
  • I signed the CLA.
  • I updated/added relevant documentation (doc comments with ///).

Issues checklist:

Tests checklist:

  • I added new tests to check the change I am making.

AI-tooling checklist:

  • I did not use any AI tooling in creating this PR.
  • I did use AI tooling, and...
    • I read the AI contributions guidelines and agree to follow them.
    • I reviewed all AI-generated code before opening this PR.
    • I understand and am able to discuss the code in this PR.
    • I have verifed the accuracy of any AI-generated text included in the PR description.
    • I commit to verifying the accuracy of any AI-generated code or text that I upload in response to review comments.

Feature-change checklist:

  • This PR does not change the DevTools UI or behavior and...
  • This PR does change the DevTools UI or behavior and...
    • I added an entry to packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md.
    • I included before/after screenshots and/or a GIF demo of the new UI to my PR description. (Attached in Before and after.)
    • I ran the DevTools app locally to manually verify my changes.

build.yaml badge

If you need help, consider asking for help on Discord.

The Network screen toolbar and the shared footer status line overflowed and
overlapped at narrow widths.

Network toolbar: below 600 px the search field moves to its own row, and below
900 px the filter field moves to its own row. Layout at 900 px and above is
unchanged.

Footer (StatusLine, shared by all screens): footer text is truncated instead of
overflowing. Below 900 px the video tutorial link and, when DevTools is embedded,
the embedded actions move into a More actions menu. Each menu item runs the same
action as its inline counterpart. Below 600 px the disconnected status shows an
icon with a tooltip instead of text.

Fixes flutter#10004

Assisted-by: Devin AI
@NemesisDevX
NemesisDevX marked this pull request as ready for review October 28, 2026 11:39

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request improves responsiveness on narrow screens for the DevTools status line and the Network screen toolbar, preventing layout overflows and overlaps. It wraps status line items in flexible widgets, moves secondary actions into an overflow menu on compact widths, and wraps the Network screen's search and filter fields onto their own rows when space is limited. Comprehensive responsive layout tests and test utilities are also added. The review feedback suggests using Flexible instead of Expanded for the page status in the status line to maintain proper spacing, and utilizing GlobalKeys for the search and filter fields in the Network screen to preserve widget state and focus during responsive reparenting.

pageStatus,
// The page status needs to be flexible so that the status line can
// shrink to fit narrow screens without overflowing.
Expanded(child: pageStatus),

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.

medium

[CONCERN] Using Expanded forces the pageStatus widget to occupy all remaining horizontal space, which overrides the MainAxisAlignment.spaceBetween alignment of the parent Row. This can cause visual layout inconsistencies and push other footer elements to the extreme edges even when there is plenty of screen width.\n\nUsing Flexible (which defaults to FlexFit.loose) allows the pageStatus to only take up the space it actually needs when it is short, preserving the intended spaceBetween spacing, while still constraining it and allowing it to shrink (preventing overflow) on narrow screens.

Suggested change
Expanded(child: pageStatus),
Flexible(child: pageStatus),

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done — switched to Flexible. With Expanded the page status absorbed all leftover space inside its own box, which changed the even spaceBetween spacing the footer had before this change. Flexible restores the previous wide-screen spacing while still shrinking (and ellipsizing) when space is constrained. Added tests asserting the status keeps its natural width on wide screens and that the connection status stays right-aligned.

Comment on lines +216 to +225
final searchField = SearchField<NetworkController>(
searchController: controller,
searchFieldWidth: screenWidth <= MediaSize.xs
? defaultSearchFieldWidth
: wideSearchFieldWidth,
);
final filterField = StandaloneFilterField<NetworkRequest>(
controller: controller,
filteredItem: 'request',
);

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.

medium

[CONCERN] When the screen width crosses the responsive thresholds (MediaSize.xs or MediaSize.s), the searchField and filterField are reparented to different rows in the widget tree. In Flutter, moving a widget to a different position in the tree causes it to lose its state (including focus and cursor position) unless a GlobalKey is used.\n\nTo preserve focus and text selection during resizing, please define two GlobalKeys in your _NetworkProfilerControlsState class and pass them to the fields:\n\ndart\n// In _NetworkProfilerControlsState:\nfinal _searchFieldKey = GlobalKey();\nfinal _filterFieldKey = GlobalKey();\n

Suggested change
final searchField = SearchField<NetworkController>(
searchController: controller,
searchFieldWidth: screenWidth <= MediaSize.xs
? defaultSearchFieldWidth
: wideSearchFieldWidth,
);
final filterField = StandaloneFilterField<NetworkRequest>(
controller: controller,
filteredItem: 'request',
);
final searchField = SearchField<NetworkController>(\n key: _searchFieldKey,\n searchController: controller,\n searchFieldWidth: screenWidth <= MediaSize.xs\n ? defaultSearchFieldWidth\n : wideSearchFieldWidth,\n );\n final filterField = StandaloneFilterField<NetworkRequest>(\n key: _filterFieldKey,\n controller: controller,\n filteredItem: 'request',\n );

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done — the fields now have stable GlobalKeys held by _NetworkProfilerControlsState. Verified in a widget test that resizes across the 600 and 900 breakpoints in both directions: without keys, each reparent recreated the filter field's State and internal TextEditingController (selection and focus lost, text re-seeded from the normalized query), and the remounted search field's autofocus stole focus. With keys, text, selection, focus, and State identity survive every crossing.

Give the Network search and filter fields stable keys so their widget
state (text, selection, and focus) survives being reparented between
toolbar rows when the window crosses the 600 and 900 pixel breakpoints.
Previously each reparent recreated the filter field's text controller
and focus, losing the selection and focus, and the remounted search
field's autofocus stole focus.

Wrap the footer's page status in Flexible instead of Expanded so it
keeps its natural width and the status line's spaceBetween alignment
keeps spacing even on wide screens, matching the layout before the
responsive change. It still shrinks below its natural width, and
ellipsizes, when space is constrained.

Assisted-by: Devin AI

This branch has not been deployed

No deployments
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.

DevTools Network tab header and footer toolbar controls overlap on narrow screens

1 participant