Skip to content

Commit

Permalink
Fix DevTools extension analytics (#6651)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenzieschmoll authored Nov 3, 2023
1 parent 4474099 commit 348a6c7
Show file tree
Hide file tree
Showing 21 changed files with 193 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class _EmbeddedExtensionViewState extends State<EmbeddedExtensionView> {
super.initState();
ga.impression(
gac.DevToolsExtensionEvents.extensionScreenName(
widget.controller.extensionConfig.name,
widget.controller.extensionConfig,
),
gac.DevToolsExtensionEvents.embeddedExtension.name,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ class _ExtensionScreenBodyState extends State<_ExtensionScreenBody> {

void _init() {
ga.screen(
gac.DevToolsExtensionEvents.extensionScreenName(
widget.extensionConfig.name,
),
gac.DevToolsExtensionEvents.extensionScreenName(widget.extensionConfig),
);
extensionController =
createEmbeddedExtensionController(widget.extensionConfig)..init();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class EmbeddedExtensionHeader extends StatelessWidget {
url: extension.issueTrackerLink,
gaScreenName: gac.DevToolsExtensionEvents.extensionScreenId.name,
gaSelectedItemDescription:
gac.DevToolsExtensionEvents.extensionFeedback(extensionName),
gac.DevToolsExtensionEvents.extensionFeedback(extension),
),
context: context,
),
Expand Down Expand Up @@ -95,7 +95,7 @@ class EmbeddedExtensionHeader extends StatelessWidget {
ga.select(
gac.DevToolsExtensionEvents.extensionScreenId.name,
gac.DevToolsExtensionEvents.extensionForceReload(
extension.displayName,
extension,
),
);
onForceReload();
Expand Down Expand Up @@ -172,9 +172,7 @@ class DisableExtensionDialog extends StatelessWidget {
onPressed: () {
ga.select(
gac.DevToolsExtensionEvents.extensionScreenId.name,
gac.DevToolsExtensionEvents.extensionDisableManual(
extension.displayName,
),
gac.DevToolsExtensionEvents.extensionDisableManual(extension),
);
unawaited(
extensionService.setExtensionEnabledState(
Expand Down Expand Up @@ -205,7 +203,6 @@ class EnableExtensionPrompt extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final extensionName = extension.displayName;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
Expand Down Expand Up @@ -245,7 +242,7 @@ class EnableExtensionPrompt extends StatelessWidget {
label: 'Enable',
gaScreen: gac.DevToolsExtensionEvents.extensionScreenId.name,
gaSelection: gac.DevToolsExtensionEvents.extensionEnablePrompt(
extensionName,
extension,
),
elevated: true,
onPressed: () {
Expand All @@ -262,7 +259,7 @@ class EnableExtensionPrompt extends StatelessWidget {
label: 'No, hide this screen',
gaScreen: gac.DevToolsExtensionEvents.extensionScreenId.name,
gaSelection: gac.DevToolsExtensionEvents.extensionDisablePrompt(
extensionName,
extension,
),
onPressed: () {
unawaited(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ class ExtensionSetting extends StatelessWidget {
onPressed: () {
ga.select(
gac.DevToolsExtensionEvents.extensionSettingsId.name,
gac.DevToolsExtensionEvents.extensionEnableManual(
extension.name.toLowerCase(),
),
gac.DevToolsExtensionEvents.extensionEnableManual(extension),
);
unawaited(
extensionService.setExtensionEnabledState(
Expand All @@ -161,9 +159,7 @@ class ExtensionSetting extends StatelessWidget {
onPressed: () {
ga.select(
gac.DevToolsExtensionEvents.extensionSettingsId.name,
gac.DevToolsExtensionEvents.extensionDisableManual(
extension.name.toLowerCase(),
),
gac.DevToolsExtensionEvents.extensionDisableManual(extension),
);
unawaited(
extensionService.setExtensionEnabledState(
Expand Down
2 changes: 2 additions & 0 deletions packages/devtools_app/lib/src/shared/analytics/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:devtools_shared/devtools_extensions.dart';

import '../screen.dart';

part 'constants/_cpu_profiler_constants.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,36 @@ enum DevToolsExtensionEvents {
embeddedExtension;

/// Event sent via [ga.screen] when an extension screen is opened.
static String extensionScreenName(String name) => 'extension-$name';
static String extensionScreenName(DevToolsExtensionConfig ext) =>
'extension-${ext.analyticsSafeName}';

/// Event sent when a user clicks the "Report an issue" link on an extension
/// screen.
static String extensionFeedback(String name) => 'extensionFeedback-$name';
static String extensionFeedback(DevToolsExtensionConfig ext) =>
'extensionFeedback-${ext.analyticsSafeName}';

/// Event sent when an extension is enabled because a user manually enabled
/// it from the extensions settings menu.
static String extensionEnableManual(String name) =>
'extensionEnable-manual-$name';
static String extensionEnableManual(DevToolsExtensionConfig ext) =>
'extensionEnable-manual-${ext.analyticsSafeName}';

/// Event sent when an extension is enabled because a user answered the
/// enablement prompt with "Enable".
static String extensionEnablePrompt(String name) =>
'extensionEnable-prompt-$name';
static String extensionEnablePrompt(DevToolsExtensionConfig ext) =>
'extensionEnable-prompt-${ext.analyticsSafeName}';

/// Event sent when an extension is disabled because a user manually disabled
/// it from the [DisableExtensionDialog] or the main extensions settings menu.
static String extensionDisableManual(String name) =>
'extensionDisable-manual-$name';
static String extensionDisableManual(DevToolsExtensionConfig ext) =>
'extensionDisable-manual-${ext.analyticsSafeName}';

/// Event sent when an extension is disabled because a user answered the
/// enablement prompt with "No, hide this sceen".
static String extensionDisablePrompt(String name) =>
'extensionDisable-prompt-$name';
static String extensionDisablePrompt(DevToolsExtensionConfig ext) =>
'extensionDisable-prompt-${ext.analyticsSafeName}';

/// Event sent when an extension is force reloaded from the extension screen
/// context menu.
static String extensionForceReload(String name) =>
'extensionForceReload-$name';
static String extensionForceReload(DevToolsExtensionConfig ext) =>
'extensionForceReload-${ext.analyticsSafeName}';
}
3 changes: 3 additions & 0 deletions packages/devtools_app/lib/src/shared/development_helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ final List<DevToolsExtensionConfig> debugExtensions = [
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
DevToolsExtensionConfig.versionKey: '1.0.0',
DevToolsExtensionConfig.pathKey: '/path/to/foo',
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
}),
DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.nameKey: 'bar',
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
DevToolsExtensionConfig.versionKey: '2.0.0',
DevToolsExtensionConfig.materialIconCodePointKey: 0xe638,
DevToolsExtensionConfig.pathKey: '/path/to/bar',
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
}),
DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.nameKey: 'provider',
Expand All @@ -78,6 +80,7 @@ final List<DevToolsExtensionConfig> debugExtensions = [
DevToolsExtensionConfig.versionKey: '3.0.0',
DevToolsExtensionConfig.materialIconCodePointKey: 0xe50a,
DevToolsExtensionConfig.pathKey: '/path/to/provider',
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
}),
];

Expand Down
2 changes: 1 addition & 1 deletion packages/devtools_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ dependencies:
dds_service_extensions: ^1.6.0
devtools_app_shared: ^0.0.7
devtools_extensions: ^0.0.10
devtools_shared: ^5.0.0
devtools_shared: ^6.0.1
file: ">=6.0.0 <8.0.0"
file_selector: ^0.8.0
file_selector_linux: ^0.0.2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2023 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:devtools_app/src/shared/analytics/constants.dart';
import 'package:flutter_test/flutter_test.dart';

import '../test_infra/test_data/extensions.dart';

void main() {
group('DevTools extension analytics', () {
test(
'uses extension name for public package',
() {
final public = providerExtension;
expect(public.isPubliclyHosted, true);
expect(public.name, 'provider');
expect(public.analyticsSafeName, 'provider');
expect(
DevToolsExtensionEvents.extensionScreenName(public),
'extension-provider',
);
expect(
DevToolsExtensionEvents.extensionFeedback(public),
'extensionFeedback-provider',
);
expect(
DevToolsExtensionEvents.extensionEnableManual(public),
'extensionEnable-manual-provider',
);
expect(
DevToolsExtensionEvents.extensionEnablePrompt(public),
'extensionEnable-prompt-provider',
);
expect(
DevToolsExtensionEvents.extensionDisableManual(public),
'extensionDisable-manual-provider',
);

expect(
DevToolsExtensionEvents.extensionDisablePrompt(public),
'extensionDisable-prompt-provider',
);
expect(
DevToolsExtensionEvents.extensionForceReload(public),
'extensionForceReload-provider',
);
},
);

test(
'does not use extension name for private package',
() {
final private = fooExtension;
expect(private.isPubliclyHosted, false);
expect(private.name, 'Foo');
expect(private.analyticsSafeName, 'private');
expect(
DevToolsExtensionEvents.extensionScreenName(private),
'extension-private',
);
expect(
DevToolsExtensionEvents.extensionFeedback(private),
'extensionFeedback-private',
);
expect(
DevToolsExtensionEvents.extensionEnableManual(private),
'extensionEnable-manual-private',
);
expect(
DevToolsExtensionEvents.extensionEnablePrompt(private),
'extensionEnable-prompt-private',
);
expect(
DevToolsExtensionEvents.extensionDisableManual(private),
'extensionDisable-manual-private',
);

expect(
DevToolsExtensionEvents.extensionDisablePrompt(private),
'extensionDisable-prompt-private',
);
expect(
DevToolsExtensionEvents.extensionForceReload(private),
'extensionForceReload-private',
);
},
);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ final fooExtension = DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
DevToolsExtensionConfig.versionKey: '1.0.0',
DevToolsExtensionConfig.pathKey: '/path/to/foo',
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
});

final barExtension = DevToolsExtensionConfig.parse({
Expand All @@ -19,6 +20,7 @@ final barExtension = DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.versionKey: '2.0.0',
DevToolsExtensionConfig.materialIconCodePointKey: 0xe638,
DevToolsExtensionConfig.pathKey: '/path/to/bar',
DevToolsExtensionConfig.isPubliclyHostedKey: 'false',
});

final providerExtension = DevToolsExtensionConfig.parse({
Expand All @@ -28,4 +30,5 @@ final providerExtension = DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.versionKey: '3.0.0',
DevToolsExtensionConfig.materialIconCodePointKey: 0xe50a,
DevToolsExtensionConfig.pathKey: '/path/to/provider',
DevToolsExtensionConfig.isPubliclyHostedKey: 'true',
});
2 changes: 1 addition & 1 deletion packages/devtools_app_shared/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Soften breaking change from 0.0.6 to add the `profilePlatformChannels` service extension,
improving backwards compatibility for older versions of Flutter.
* Bump `package:vm_service` dependency to ^13.0.0.
* Bump the `package:devtools_shared` dependency to ^6.0.0.
* Bump the `package:devtools_shared` dependency to ^6.0.1.
* Remove public getter `libraryRef`, and public methods `getLibrary` and `retrieveFullValueAsString` from `EvalOnDartLibrary`.
* Change `toString` output for `UnknownEvalException`, `EvalSentinelException`, and `EvalErrorException`.
* Remove public getters `flutterVersionSummary`, `frameworkVersionSummary`, and `engineVersionSummary` from `FlutterVersion`.
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools_app_shared/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ environment:

dependencies:
collection: ^1.15.0
devtools_shared: ^6.0.0
devtools_shared: ^6.0.1
flutter:
sdk: flutter
logging: ^1.1.1
Expand Down
2 changes: 1 addition & 1 deletion packages/devtools_extensions/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ DevTools extension.
* Add an example `launch.json` file in the `example/foo` directory.
* Clean up the package readme to make instructions Windows-compatible.
* Update the README with instructions for joining the Flutter Discord server.
* Bump `package:devtools_shared` dependency to ^6.0.0
* Bump `package:devtools_shared` dependency to ^6.0.1
* Bump `package:devtools_app_shared` dependency to ^0.0.7
* Bump `package:vm_service` dependency to ^13.0.0.

Expand Down
2 changes: 1 addition & 1 deletion packages/devtools_extensions/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ executables:

dependencies:
args: ^2.4.2
devtools_shared: ^6.0.0
devtools_shared: ^6.0.1
devtools_app_shared: ^0.0.7
flutter:
sdk: flutter
Expand Down
3 changes: 3 additions & 0 deletions packages/devtools_shared/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 6.0.1
* Add field `isPublic` to `DevToolsExtensionConfig`.

# 6.0.0
* Bump `package:vm_service` dependency to ^13.0.0.
* Remove `ServiceCreator` typedef and replace usages with `VmServiceFactory` typedef from `package:vm_service`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ class ExtensionsManager {
}
for (final extension in extensions) {
final config = extension.config;
// TODO(https://github.com/dart-lang/pub/issues/4042): make this check
// more robust.
final isPubliclyHosted = (extension.rootUri.path.contains('pub.dev') ||
extension.rootUri.path.contains('pub.flutter-io.cn'))
.toString();

// This should be relative to the 'extension/devtools/' directory and
// defaults to 'build';
final relativeExtensionLocation =
Expand All @@ -93,6 +99,7 @@ class ExtensionsManager {
final extensionConfig = DevToolsExtensionConfig.parse({
...config,
DevToolsExtensionConfig.pathKey: location,
DevToolsExtensionConfig.isPubliclyHostedKey: isPubliclyHosted,
});
devtoolsExtensions.add(extensionConfig);
} on StateError catch (e) {
Expand Down
Loading

0 comments on commit 348a6c7

Please sign in to comment.