Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offline support for Network page #8332

Open
wants to merge 43 commits into
base: master
Choose a base branch
from

Conversation

hrajwade96
Copy link
Contributor

@hrajwade96 hrajwade96 commented Sep 21, 2024

Adding offline support to Network page.

issue link - #4470

List which issues are fixed by this PR.

Please add a note to packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md if your change requires release notes. Otherwise, add the 'release-notes-not-required' label to the PR.

Pre-launch 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 listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or there is a reason for not adding tests.

build.yaml badge

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

@hrajwade96 hrajwade96 requested review from bkonyi, kenzieschmoll and a team as code owners September 21, 2024 09:19
@hrajwade96 hrajwade96 marked this pull request as draft September 21, 2024 09:19
@hrajwade96 hrajwade96 changed the title added initial implementation Offline support for Network page Sep 21, 2024
@kenzieschmoll
Copy link
Member

@hrajwade96 is this PR ready for review or is this still a work in progress?

@hrajwade96
Copy link
Contributor Author

@hrajwade96 is this PR ready for review or is this still a work in progress?

@kenzieschmoll just finishing up few things, I will mark it ready soon

@hrajwade96 hrajwade96 marked this pull request as ready for review October 2, 2024 17:19
Copy link
Member

@kenzieschmoll kenzieschmoll left a comment

Choose a reason for hiding this comment

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

Just a couple more comments. Thank you for all your work on this change!

@kenzieschmoll
Copy link
Member

Looks like there are several failing checks. Please also add an entry to NEXT_RELEASE_NOTES.md so that the release notes check passes.

@kenzieschmoll
Copy link
Member

You will likely have several merge conflicts after pulling in the tip of the master branch. A change just landed that upgraded the Flutter version used in DevTools, which updated to a new version of the dart formatter. Here's what I recommend to make this merge simpler for you:

  1. Merge the master branch into your branch.
  2. For all conflicts, accept your revision of the file..
  3. Run dt update-flutter-sdk. This will update the flutter sdk contained at tool/flutter-sdk to the version used on the DevTools CI.
  4. Run tool/flutter-sdk/bin/dart format from the devtools_app directory. This will format your files with your changes to use the new formatter.

…fline_support

# Conflicts:
#	packages/devtools_app/lib/src/screens/network/har_data_entry.dart
#	packages/devtools_app/lib/src/screens/network/network_screen.dart
#	packages/devtools_app/lib/src/shared/http/http_request_data.dart
…fline_support

# Conflicts:
#	packages/devtools_app/lib/src/screens/network/network_screen.dart
#	packages/devtools_app/test/screens/network/offline_data_test.dart
#	packages/devtools_app/test/screens/network/sample_network_offline_data.json
@hrajwade96 hrajwade96 force-pushed the network_screen_offline_support branch from aebe0d8 to 2a9cacf Compare December 27, 2024 07:03
@hrajwade96
Copy link
Contributor Author

You will likely have several merge conflicts after pulling in the tip of the master branch. A change just landed that upgraded the Flutter version used in DevTools, which updated to a new version of the dart formatter. Here's what I recommend to make this merge simpler for you:

  1. Merge the master branch into your branch.
  2. For all conflicts, accept your revision of the file..
  3. Run dt update-flutter-sdk. This will update the flutter sdk contained at tool/flutter-sdk to the version used on the DevTools CI.
  4. Run tool/flutter-sdk/bin/dart format from the devtools_app directory. This will format your files with your changes to use the new formatter.

@kenzieschmoll can you run the checks again, I have done the above steps, formatted the code and updated the release notes as well.

@hrajwade96
Copy link
Contributor Author

hrajwade96 commented Jan 6, 2025

You will likely have several merge conflicts after pulling in the tip of the master branch. A change just landed that upgraded the Flutter version used in DevTools, which updated to a new version of the dart formatter. Here's what I recommend to make this merge simpler for you:

  1. Merge the master branch into your branch.
  2. For all conflicts, accept your revision of the file..
  3. Run dt update-flutter-sdk. This will update the flutter sdk contained at tool/flutter-sdk to the version used on the DevTools CI.
  4. Run tool/flutter-sdk/bin/dart format from the devtools_app directory. This will format your files with your changes to use the new formatter.

@kenzieschmoll can you run the checks again, I have done the above steps, formatted the code and updated the release notes as well.

I pushed a minor change that I had missed pushing earlier which was the primary cause of the checks failing.
@kenzieschmoll can you re-run

@kenzieschmoll
Copy link
Member

kenzieschmoll commented Jan 13, 2025

Looks like you still have some failing tests. Based on the errors it looks like you may need to set a global in the test setup for the failing tests: setGlobal(OfflineDataController, OfflineDataController());

You can verify the tests pass locally by running flutter test test/screens/network/

@kenzieschmoll
Copy link
Member

kenzieschmoll commented Jan 14, 2025

Getting closer. Another failing test: devtools/packages/devtools_app/test/shared/framework/visible_screens_test.dart.

Consider running all tests locally flutter test test/ to ensure tests are passing.

@kenzieschmoll kenzieschmoll mentioned this pull request Jan 14, 2025
7 tasks
@hrajwade96
Copy link
Contributor Author

hrajwade96 commented Jan 15, 2025

Getting closer. Another failing test: devtools/packages/devtools_app/test/shared/framework/visible_screens_test.dart.

Consider running all tests locally flutter test test/ to ensure tests are passing.

Yes I've fixed this one, I ran locally now there's just one test (below one) failing locally but mostly it's timezone bound, hence although it's failing locally, it should pass here.

    test('TimestampColumn', () {
      final column = TimestampColumn();
      final getRequest = findRequestById('1');

      // The hours field may be unreliable since it depends on the timezone the
      // test is running in.
      expect(column.getDisplayValue(getRequest), contains(':45:26.279'));
    });

@kenzieschmoll
Copy link
Member

A couple things look like they are still missing from this PR. I checked the code out locally and noticed that we do not have a way to export the offline network data. This is because the OpenSaveButtonGroup was not added to _NetworkProfilerControlsState. Please apply this patch to the _NetworkProfilerControlsState.build method:

    return Row(
      children: [
        if (!widget.offline) ...[
          StartStopRecordingButton(
            recording: _recording,
            onPressed:
                () async => await widget.controller.togglePolling(!_recording),
            tooltipOverride:
                _recording
                    ? 'Stop recording network traffic'
                    : 'Resume recording network traffic',
            minScreenWidthForTextBeforeScaling: double.infinity,
            gaScreen: gac.network,
            gaSelection: _recording ? gac.pause : gac.resume,
          ),
          const SizedBox(width: denseSpacing),
          ClearButton(
            minScreenWidthForTextBeforeScaling:
                _NetworkProfilerControls._includeTextWidth,
            gaScreen: gac.network,
            gaSelection: gac.clear,
            onPressed: widget.controller.clear,
          ),
          const SizedBox(width: denseSpacing),
          DownloadButton(
            tooltip: 'Download as .har file',
            minScreenWidthForTextBeforeScaling:
                _NetworkProfilerControls._includeTextWidth,
            onPressed: widget.controller.exportAsHarFile,
            gaScreen: gac.network,
            gaSelection: gac.NetworkEvent.downloadAsHar.name,
          ),
          const SizedBox(width: denseSpacing),
          // TODO(kenz): fix focus issue when state is refreshed
          Expanded(
            child: SearchField<NetworkController>(
              searchController: widget.controller,
              searchFieldEnabled: hasRequests,
              searchFieldWidth:
                  screenWidth <= MediaSize.xs
                      ? defaultSearchFieldWidth
                      : wideSearchFieldWidth,
            ),
          ),
          const SizedBox(width: denseSpacing),
          Expanded(
            child: StandaloneFilterField<NetworkRequest>(
              controller: widget.controller,
              filteredItem: 'request',
            ),
          ),
          const SizedBox(width: denseSpacing),
          OpenSaveButtonGroup(
            screenId: ScreenMetaData.performance.id,
            onSave: widget.controller.exportData,
          ),
        ],
      ],
    );

Once I added these buttons and then attempted to export network data, I am seeing an exception:

══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
The following HttpProfileRequestError was thrown while handling a gesture:
SocketException: Connection refused (OS Error: Connection refused, errno = 61), address = 127.0.0.1,
port = 53461.

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 307:3        throw_
errors.dart:307
packages/vm_service/src/dart_io_extensions.dart 565:7                              [_returnIfNoError]
dart_io_extensions.dart:565
packages/vm_service/src/dart_io_extensions.dart 542:40                             get headers
dart_io_extensions.dart:542
packages/devtools_app/src/shared/http/http_request_data.dart 387:41                HttpProfileRequestDataExtension.toJson
http_request_data.dart:387
packages/devtools_app/src/shared/http/http_request_data.dart 375:50                HttpProfileRequestExtension.toJson
http_request_data.dart:375
packages/devtools_app/src/shared/http/http_request_data.dart 81:44                 toJson
http_request_data.dart:81
packages/devtools_app/src/screens/network/offline_network_data.dart 87:39          <fn>
offline_network_data.dart:87
dart-sdk/lib/internal/iterable.dart 442:31                                         elementAt
iterable.dart:442
dart-sdk/lib/internal/iterable.dart 371:26                                         moveNext
iterable.dart:371
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 1127:20  next
operations.dart:1127
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 358:14                 of
core_patch.dart:358
dart-sdk/lib/internal/iterable.dart 224:7                                          toList
iterable.dart:224
packages/devtools_app/src/screens/network/offline_network_data.dart 87:39          toJson
offline_network_data.dart:87
packages/devtools_app/src/screens/network/network_controller.dart 470:24           prepareOfflineScreenData
network_controller.dart:470
packages/devtools_app/src/shared/offline/offline_data.dart 188:34                  exportData
offline_data.dart:188
packages/devtools_app/src/shared/ui/file_import.dart 63:21                         <fn>
file_import.dart:63
packages/flutter/src/material/ink_well.dart 1185:21                                handleTap

@hrajwade96
Copy link
Contributor Author

hrajwade96 commented Jan 15, 2025

A couple things look like they are still missing from this PR. I checked the code out locally and noticed that we do not have a way to export the offline network data. This is because the OpenSaveButtonGroup was not added to _NetworkProfilerControlsState. Please apply this patch to the _NetworkProfilerControlsState.build method:

    return Row(
      children: [
        if (!widget.offline) ...[
          StartStopRecordingButton(
            recording: _recording,
            onPressed:
                () async => await widget.controller.togglePolling(!_recording),
            tooltipOverride:
                _recording
                    ? 'Stop recording network traffic'
                    : 'Resume recording network traffic',
            minScreenWidthForTextBeforeScaling: double.infinity,
            gaScreen: gac.network,
            gaSelection: _recording ? gac.pause : gac.resume,
          ),
          const SizedBox(width: denseSpacing),
          ClearButton(
            minScreenWidthForTextBeforeScaling:
                _NetworkProfilerControls._includeTextWidth,
            gaScreen: gac.network,
            gaSelection: gac.clear,
            onPressed: widget.controller.clear,
          ),
          const SizedBox(width: denseSpacing),
          DownloadButton(
            tooltip: 'Download as .har file',
            minScreenWidthForTextBeforeScaling:
                _NetworkProfilerControls._includeTextWidth,
            onPressed: widget.controller.exportAsHarFile,
            gaScreen: gac.network,
            gaSelection: gac.NetworkEvent.downloadAsHar.name,
          ),
          const SizedBox(width: denseSpacing),
          // TODO(kenz): fix focus issue when state is refreshed
          Expanded(
            child: SearchField<NetworkController>(
              searchController: widget.controller,
              searchFieldEnabled: hasRequests,
              searchFieldWidth:
                  screenWidth <= MediaSize.xs
                      ? defaultSearchFieldWidth
                      : wideSearchFieldWidth,
            ),
          ),
          const SizedBox(width: denseSpacing),
          Expanded(
            child: StandaloneFilterField<NetworkRequest>(
              controller: widget.controller,
              filteredItem: 'request',
            ),
          ),
          const SizedBox(width: denseSpacing),
          OpenSaveButtonGroup(
            screenId: ScreenMetaData.performance.id,
            onSave: widget.controller.exportData,
          ),
        ],
      ],
    );

Once I added these buttons and then attempted to export network data, I am seeing an exception:

══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
The following HttpProfileRequestError was thrown while handling a gesture:
SocketException: Connection refused (OS Error: Connection refused, errno = 61), address = 127.0.0.1,
port = 53461.

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 307:3        throw_
errors.dart:307
packages/vm_service/src/dart_io_extensions.dart 565:7                              [_returnIfNoError]
dart_io_extensions.dart:565
packages/vm_service/src/dart_io_extensions.dart 542:40                             get headers
dart_io_extensions.dart:542
packages/devtools_app/src/shared/http/http_request_data.dart 387:41                HttpProfileRequestDataExtension.toJson
http_request_data.dart:387
packages/devtools_app/src/shared/http/http_request_data.dart 375:50                HttpProfileRequestExtension.toJson
http_request_data.dart:375
packages/devtools_app/src/shared/http/http_request_data.dart 81:44                 toJson
http_request_data.dart:81
packages/devtools_app/src/screens/network/offline_network_data.dart 87:39          <fn>
offline_network_data.dart:87
dart-sdk/lib/internal/iterable.dart 442:31                                         elementAt
iterable.dart:442
dart-sdk/lib/internal/iterable.dart 371:26                                         moveNext
iterable.dart:371
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 1127:20  next
operations.dart:1127
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 358:14                 of
core_patch.dart:358
dart-sdk/lib/internal/iterable.dart 224:7                                          toList
iterable.dart:224
packages/devtools_app/src/screens/network/offline_network_data.dart 87:39          toJson
offline_network_data.dart:87
packages/devtools_app/src/screens/network/network_controller.dart 470:24           prepareOfflineScreenData
network_controller.dart:470
packages/devtools_app/src/shared/offline/offline_data.dart 188:34                  exportData
offline_data.dart:188
packages/devtools_app/src/shared/ui/file_import.dart 63:21                         <fn>
file_import.dart:63
packages/flutter/src/material/ink_well.dart 1185:21                                handleTap

@kenzieschmoll, I wanted to clarify my understanding based on your comment:

  1. This PR focuses solely on viewing Network data in offline mode. Importing offline data back into DevTools is planned in the upcoming PR, as we discussed earlier (If you suggest to add it as part of this PR itself we can add it here).
  2. Exporting HAR files already has a dedicated Download CTA, so I assumed adding 'OpenSaveButtonGroup' wasn't necessary at this stage.
  3. Additionally, as previously discussed, export functionality is not supported while in offline mode.
    Let me know if there are any changes to this or we can go ahead with this

@kenzieschmoll
Copy link
Member

kenzieschmoll commented Jan 15, 2025

This PR focuses solely on viewing Network data in offline mode

By this do you mean viewing data when the Network screen is showing, and then DevTools loses connection to the running app? In other words, the "review history" feature?

Importing offline data back into DevTools is planned in the upcoming PR

Okay this sounds good. Can we turn the feature flag to off then until this support is added?

How much work is left to do to support exporting the data as JSON? I would expect there is a small bit of serialization work left to ensure the data can be serialized and deserialized to JSON, but the majority of the logic is contained in this PR. Is that accurate?

(edited) UPDATE:
I have a follow on I'd like to submit after this PR. This will essentially pave the way for you to implement the full offline support for the network screen (which is exporting the data as json and being able to re-import it as json). This follow on PR I have put to gather will combine the download buttons to let the user choose which format they'd like to download data in.
Screenshot 2025-01-15 at 12 00 26 PM
Screenshot 2025-01-15 at 12 00 31 PM

This would be behind a new experiment flag networkSaveLoad so that the network disconnect experience can still be enabled while the full offline support is under development.

@kenzieschmoll
Copy link
Member

I dug a little deeper on the errors I am encountering. These exceptions occur even for the "review history" behavior. Have you tested with requests that have an error? Some of the fields on HttpProfileRequestData (from the vm_service package) will throw an exception if the request has an error (hasError). We need to make sure that the serialization logic gracefully handles all of these cases.

We should also have test coverage for this case.

Screenshot 2025-01-15 at 12 21 29 PM

@hrajwade96
Copy link
Contributor Author

I dug a little deeper on the errors I am encountering. These exceptions occur even for the "review history" behavior. Have you tested with requests that have an error? Some of the fields on HttpProfileRequestData (from the vm_service package) will throw an exception if the request has an error (hasError). We need to make sure that the serialization logic gracefully handles all of these cases.

We should also have test coverage for this case.

Screenshot 2025-01-15 at 12 21 29 PM

Ok will check this case and also add test coverage for this

@hrajwade96
Copy link
Contributor Author

By this do you mean viewing data when the Network screen is showing, and then DevTools loses connection to the running app? In other words, the "review history" feature?

Yes I meant the "review history" feature.

Okay this sounds good. Can we turn the feature flag to off then until this support is added?

Sure, so as per your next comment I think you are suggesting to enable the review history (with this PR) and add another flag which gives two options to choose the format for export, and also an import button (in the next PR).

(edited) UPDATE: I have a follow on I'd like to submit after this PR. This will essentially pave the way for you to implement the full offline support for the network screen (which is exporting the data as json and being able to re-import it as json). This follow on PR I have put to gather will combine the download buttons to let the user choose which format they'd like to download data in. Screenshot 2025-01-15 at 12 00 26 PM Screenshot 2025-01-15 at 12 00 31 PM

This would be behind a new experiment flag networkSaveLoad so that the network disconnect experience can still be enabled while the full offline support is under development.

Sure, I'll pick this up in the next PR. Could you elaborate on the key idea behind adding the option to export it as a '.json' file?

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