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

Add DevToolsExtension template to devtools_extension package #6066

Merged
merged 7 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'dart:async';
import 'dart:html' as html;
import 'dart:ui' as ui;

import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:devtools_extensions/api.dart';

import 'controller.dart';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class EmbeddedExtension extends StatelessWidget {
// TODO(kenz): if web view support for desktop is ever added, use that here.
return const Center(
child: Text(
'Cannot display the DevTools plugin.'
'Cannot display the DevTools extension.'
' IFrames are not supported on desktop platforms.',
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'dart:async';
// ignore: avoid_web_libraries_in_flutter, as designed
import 'dart:html' as html;

import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:devtools_extensions/api.dart';
import 'package:flutter/material.dart';

import '../../shared/globals.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:devtools_extensions/api.dart';

import '../../shared/primitives/auto_dispose.dart';
import '../extension_model.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ extension ExtensionConfigExtension on DevToolsExtensionConfig {
}

// TODO(kenz): remove these once the DevTools extensions feature has shipped.
final List<DevToolsExtensionConfig> debugPlugins = [
final List<DevToolsExtensionConfig> debugExtensions = [
DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.nameKey: 'foo',
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ class ExtensionService extends DisposableController

void initialize() {
addAutoDisposeListener(serviceManager.connectedState, () {
_refreshAvailablePlugins();
_refreshAvailableExtensions();
});
}

// TODO(kenz): actually look up the available plugins from the server, based
// on the root path(s) from the available isolate(s).
// TODO(kenz): actually look up the available extensions from devtools server,
// based on the root path(s) from the available isolate(s).
int _count = 0;
void _refreshAvailablePlugins() {
void _refreshAvailableExtensions() {
_availableExtensions.value =
debugPlugins.sublist(0, _count++ % (debugPlugins.length + 1));
debugExtensions.sublist(0, _count++ % (debugExtensions.length + 1));
}
}
8 changes: 8 additions & 0 deletions packages/devtools_extensions/lib/api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// 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.

library api;

export 'src/api/api.dart';
export 'src/api/model.dart';
5 changes: 2 additions & 3 deletions packages/devtools_extensions/lib/devtools_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

library devtools_extensions;
library template;

export 'src/api.dart';
export 'src/model.dart';
export 'src/template/devtools_extension.dart';
3 changes: 3 additions & 0 deletions packages/devtools_extensions/lib/src/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
The code in this directory is shared code that is intended to be used by
both DevTools itself and DevTools extensions. Files in this directory are
exported through the `lib/api.dart` file.
7 changes: 7 additions & 0 deletions packages/devtools_extensions/lib/src/template/README.md
Copy link
Contributor

Choose a reason for hiding this comment

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

How about moving template out of lib to example and make it separate package with its own pubspec.yaml?
You will have to create example anyway, because it will be requested by pub.get publishing code.

Copy link
Member Author

@kenzieschmoll kenzieschmoll Jul 20, 2023

Choose a reason for hiding this comment

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

the template isn't an example - it is actually the file an extension author would import to write a devtools extension.

import 'package:devtools_extensions/api.dart';
import 'package:flutter/material.dart';

import 'package:devtools_extensions/template.dart';

void main() {
  runApp(const FooPackageDevToolsExtension());
}

class FooPackageDevToolsExtension extends StatelessWidget {
  const FooPackageDevToolsExtension({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Foo DevTools Extension',
      home: const DevToolsExtension(
        child: FooExtensionHomePage(),
      ),
    );
  }
}

Copy link
Member Author

@kenzieschmoll kenzieschmoll Jul 20, 2023

Choose a reason for hiding this comment

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

renamed to devtools_extensions.dart to make that more clear

Copy link
Member Author

Choose a reason for hiding this comment

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

added an example dir in #6069

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
The code in this directory is for the DevTools extension template that package
authors will use to build DevTools extensions. Files in this directory are
exported through the `lib/devtools_extensions.dart` file.

This code is not intended to be imported into DevTools itself. Anything that
should be shared between DevTools and DevTools extensions will be under the
`src/api` directory and exported through `lib/api.dart`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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.

// ignore: avoid_web_libraries_in_flutter, as designed
import 'dart:html' as html;

import 'package:flutter/widgets.dart';
import 'package:logging/logging.dart';

import '../../api.dart';

part 'extension_manager.dart';

/// A manager that allows extensions to interact with DevTools or the DevTools
/// extensions framework.
///
/// A couple use case examples include posting messages to DevTools or
kenzieschmoll marked this conversation as resolved.
Show resolved Hide resolved
/// registering an event handler from the extension.
ExtensionManager get extensionManager => _extensionManager;
late final ExtensionManager _extensionManager;

/// A wrapper widget that initializes the [extensionManager] and establishes a
/// connection with DevTools for this extension to interact over.
class DevToolsExtension extends StatefulWidget {
const DevToolsExtension({
super.key,
required this.child,
this.eventHandlers = const {},
});

/// The root of the extension Flutter web app that is wrapped by this
/// [DevToolsExtension] wrapper.
final Widget child;

/// Event handlers registered by the extension so that it can respond to
/// DevTools events.
final Map<DevToolsExtensionEventType, ExtensionEventHandler> eventHandlers;

@override
State<DevToolsExtension> createState() => _DevToolsExtensionState();
}

class _DevToolsExtensionState extends State<DevToolsExtension> {
@override
void initState() {
super.initState();
_extensionManager = ExtensionManager().._init();
for (final handler in widget.eventHandlers.entries) {
_extensionManager.registerEventHandler(handler.key, handler.value);
}
}

@override
void dispose() {
_extensionManager._dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return widget.child;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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.

part of 'devtools_extension.dart';

final _log = Logger('devtools_extensions/extension_manager');

class ExtensionManager {
final _registeredEventHandlers =
<DevToolsExtensionEventType, ExtensionEventHandler>{};

void registerEventHandler(
DevToolsExtensionEventType event,
ExtensionEventHandler handler,
) {
_registeredEventHandlers[event] = handler;
}

// ignore: unused_element, false positive due to part files
void _init() {
html.window.addEventListener('message', _handleMessage);
}

// ignore: unused_element, false positive due to part files
void _dispose() {
_registeredEventHandlers.clear();
html.window.removeEventListener('message', _handleMessage);
}

void _handleMessage(html.Event e) {
if (e is html.MessageEvent) {
final extensionEvent = DevToolsExtensionEvent.tryParse(e.data);
if (extensionEvent != null) {
switch (extensionEvent.type) {
case DevToolsExtensionEventType.ping:
html.window.parent?.postMessage(
DevToolsExtensionEvent.pong.toJson(),
e.origin,
);
break;
case DevToolsExtensionEventType.pong:
// Ignore. DevTools extensions should not receive or handle pong
// events.
break;
case DevToolsExtensionEventType.unknown:
_log.info('Unrecognized event received by extension: ${e.data}');
kenzieschmoll marked this conversation as resolved.
Show resolved Hide resolved
break;
default:
}
_registeredEventHandlers[extensionEvent.type]?.call(extensionEvent);
}
}
}

void postMessageToDevTools(DevToolsExtensionEvent event) {
html.window.parent?.postMessage(event.toJson(), html.window.origin!);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:devtools_extensions/api.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
Expand Down Expand Up @@ -55,7 +55,7 @@ void main() {
data: {'foo': 'bar'},
);
expect(event.toJson(), {
'type': 'ping',
'type': 'pong',
'data': {'foo': 'bar'},
});

Expand Down
11 changes: 4 additions & 7 deletions packages/devtools_test/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,10 @@ dependencies:
webkit_inspection_protocol: '>=0.5.0 <2.0.0'

dependency_overrides:
# The '#OVERRIDE_FOR_DEVELOPMENT' lines are stripped out when we publish.
# All overridden dependencies are published together so there is no harm
# in treating them like they are part of a mono-repo while developing.
devtools_app: #OVERRIDE_FOR_DEVELOPMENT
path: ../devtools_app #OVERRIDE_FOR_DEVELOPMENT
devtools_shared: #OVERRIDE_FOR_DEVELOPMENT
path: ../devtools_shared #OVERRIDE_FOR_DEVELOPMENT
devtools_app:
path: ../devtools_app
devtools_shared:
path: ../devtools_shared

dev_dependencies:
build_runner: ^2.3.3
Expand Down
7 changes: 6 additions & 1 deletion tool/bots.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,16 @@ if [ "$BOT" = "main" ]; then
# Analyze the code
repo_tool analyze

# Test the devtools_shared package tests on the main bot.
popd

# Test the devtools_shared and devtools_extensions package tests on the main bot.
pushd packages/devtools_shared
echo `pwd`
flutter test test/
popd

pushd packages/devtools_extensions
echo `pwd`
flutter test test/
popd

Expand Down