Skip to content

Commit

Permalink
Add a server endpoint for serving devtools extensions (#6094)
Browse files Browse the repository at this point in the history
  • Loading branch information
kenzieschmoll authored Jul 26, 2023
1 parent 76d93bd commit 5d062a7
Show file tree
Hide file tree
Showing 13 changed files with 392 additions and 111 deletions.
2 changes: 1 addition & 1 deletion packages/devtools_app/lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

import 'dart:async';

import 'package:devtools_shared/devtools_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'example/conditional_screen.dart';
import 'extensions/extension_model.dart';
import 'extensions/extension_screen.dart';
import 'framework/framework_core.dart';
import 'framework/home_screen.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
// found in the LICENSE file.

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

import '../../shared/primitives/auto_dispose.dart';
import '../extension_model.dart';
import '_controller_desktop.dart' if (dart.library.html) '_controller_web.dart';

EmbeddedExtensionControllerImpl createEmbeddedExtensionController(
Expand Down
83 changes: 0 additions & 83 deletions packages/devtools_app/lib/src/extensions/extension_model.dart

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +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_shared/devtools_extensions.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

Expand All @@ -13,7 +14,6 @@ import '../shared/screen.dart';
import '../shared/theme.dart';
import 'embedded/controller.dart';
import 'embedded/view.dart';
import 'extension_model.dart';

class ExtensionScreen extends Screen {
ExtensionScreen(this.extensionConfig)
Expand Down Expand Up @@ -155,3 +155,10 @@ class EmbeddedExtensionHeader extends StatelessWidget {
);
}
}

extension ExtensionConfigExtension on DevToolsExtensionConfig {
IconData get icon => IconData(
materialIconCodePoint,
fontFamily: 'MaterialIcons',
);
}
27 changes: 26 additions & 1 deletion packages/devtools_app/lib/src/extensions/extension_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
// 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 'package:flutter/foundation.dart';

import '../shared/globals.dart';
import '../shared/primitives/auto_dispose.dart';
import 'extension_model.dart';

class ExtensionService extends DisposableController
with AutoDisposeControllerMixin {
Expand All @@ -28,3 +28,28 @@ class ExtensionService extends DisposableController
debugExtensions.sublist(0, _count++ % (debugExtensions.length + 1));
}
}

// TODO(kenz): remove these once the DevTools extensions feature has shipped.
final List<DevToolsExtensionConfig> debugExtensions = [
DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.nameKey: 'foo',
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
DevToolsExtensionConfig.versionKey: '1.0.0',
DevToolsExtensionConfig.pathKey: '/path/to/foo',
}),
DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.nameKey: 'bar',
DevToolsExtensionConfig.issueTrackerKey: 'www.google.com',
DevToolsExtensionConfig.versionKey: '2.0.0',
DevToolsExtensionConfig.materialIconCodePointKey: 0xe638,
DevToolsExtensionConfig.pathKey: '/path/to/bar',
}),
DevToolsExtensionConfig.parse({
DevToolsExtensionConfig.nameKey: 'provider',
DevToolsExtensionConfig.issueTrackerKey:
'https://github.com/rrousselGit/provider/issues',
DevToolsExtensionConfig.versionKey: '3.0.0',
DevToolsExtensionConfig.materialIconCodePointKey: 0xe50a,
DevToolsExtensionConfig.pathKey: '/path/to/provider',
}),
];
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// ignore_for_file: avoid-unused-parameters
import 'dart:async';

import 'package:devtools_shared/devtools_extensions.dart';

import '../../primitives/utils.dart';

const unsupportedMessage =
Expand Down Expand Up @@ -75,6 +77,12 @@ Future<DevToolsJsonFile?> requestTestAppSizeFile(String path) async {
throw Exception(unsupportedMessage);
}

Future<List<DevToolsExtensionConfig>> refreshAvailableExtensions(
String? rootPath,
) async {
return [];
}

void logWarning() {
throw Exception(unsupportedMessage);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import 'dart:convert';
// ignore: avoid_web_libraries_in_flutter, as designed
import 'dart:html';

import 'package:collection/collection.dart';
import 'package:devtools_shared/devtools_extensions.dart';
import 'package:devtools_shared/devtools_shared.dart';
import 'package:logging/logging.dart';

Expand Down Expand Up @@ -337,6 +339,32 @@ DevToolsJsonFile _devToolsJsonFileFromResponse(
);
}

Future<List<DevToolsExtensionConfig>> refreshAvailableExtensions(
String? rootPath,
) async {
if (isDevToolsServerAvailable) {
final uri = Uri(
path: apiServeAvailableExtensions,
queryParameters: {extensionRootPathPropertyName: rootPath},
);
final resp = await request(uri.toString());
if (resp?.status == HttpStatus.ok) {
final parsedResult = json.decode(resp!.responseText!);
final extensionsAsJson =
(parsedResult[extensionsResultPropertyName]! as List<Object?>)
.whereNotNull()
.cast<Map<String, Object?>>();
return extensionsAsJson
.map((p) => DevToolsExtensionConfig.parse(p))
.toList();
} else {
logWarning(resp, apiServeAvailableExtensions);
return [];
}
}
return [];
}

void logWarning(HttpRequest? response, String apiType, [String? respText]) {
_log.warning(
'HttpRequest $apiType failed status = ${response?.status}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import 'package:devtools_app/devtools_app.dart';
import 'package:devtools_app/src/extensions/embedded/view.dart';
import 'package:devtools_app/src/extensions/extension_model.dart';
import 'package:devtools_app/src/extensions/extension_screen.dart';
import 'package:devtools_shared/src/extensions/extension_model.dart';
import 'package:devtools_test/devtools_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Expand Down
6 changes: 6 additions & 0 deletions packages/devtools_shared/lib/devtools_extensions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// 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.

export 'src/extensions/extension_manager.dart';
export 'src/extensions/extension_model.dart';
57 changes: 35 additions & 22 deletions packages/devtools_shared/lib/src/devtools_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,77 @@
// found in the LICENSE file.

/// All server APIs prefix:
const String apiPrefix = 'api/';
const apiPrefix = 'api/';

/// Flutter GA properties APIs:
const String apiGetFlutterGAEnabled = '${apiPrefix}getFlutterGAEnabled';
const String apiGetFlutterGAClientId = '${apiPrefix}getFlutterGAClientId';
const apiGetFlutterGAEnabled = '${apiPrefix}getFlutterGAEnabled';
const apiGetFlutterGAClientId = '${apiPrefix}getFlutterGAClientId';

/// DevTools GA properties APIs:
const String apiResetDevTools = '${apiPrefix}resetDevTools';
const String apiGetDevToolsFirstRun = '${apiPrefix}getDevToolsFirstRun';
const String apiGetDevToolsEnabled = '${apiPrefix}getDevToolsEnabled';
const String apiSetDevToolsEnabled = '${apiPrefix}setDevToolsEnabled';
const apiResetDevTools = '${apiPrefix}resetDevTools';
const apiGetDevToolsFirstRun = '${apiPrefix}getDevToolsFirstRun';
const apiGetDevToolsEnabled = '${apiPrefix}getDevToolsEnabled';
const apiSetDevToolsEnabled = '${apiPrefix}setDevToolsEnabled';

/// Property name to apiSetDevToolsEnabled the DevToolsEnabled is the name used
/// in queryParameter:
const String devToolsEnabledPropertyName = 'enabled';
const devToolsEnabledPropertyName = 'enabled';

/// Survey properties APIs:
/// setActiveSurvey sets the survey property to fetch and save JSON values e.g., Q1-2020
const String apiSetActiveSurvey = '${apiPrefix}setActiveSurvey';
const apiSetActiveSurvey = '${apiPrefix}setActiveSurvey';

/// Survey name passed in apiSetActiveSurvey, the activeSurveyName is the property name
/// passed as a queryParameter and is the property in ~/.devtools too.
const String activeSurveyName = 'activeSurveyName';
const activeSurveyName = 'activeSurveyName';

/// Returns the surveyActionTaken of the activeSurvey (apiSetActiveSurvey).
const String apiGetSurveyActionTaken = '${apiPrefix}getSurveyActionTaken';
const apiGetSurveyActionTaken = '${apiPrefix}getSurveyActionTaken';

/// Sets the surveyActionTaken of the of the activeSurvey (apiSetActiveSurvey).
const String apiSetSurveyActionTaken = '${apiPrefix}setSurveyActionTaken';
const apiSetSurveyActionTaken = '${apiPrefix}setSurveyActionTaken';

/// Property name to apiSetSurveyActionTaken the surveyActionTaken is the name
/// passed in queryParameter:
const String surveyActionTakenPropertyName = 'surveyActionTaken';
const surveyActionTakenPropertyName = 'surveyActionTaken';

/// Returns the surveyShownCount of the of the activeSurvey (apiSetActiveSurvey).
const String apiGetSurveyShownCount = '${apiPrefix}getSurveyShownCount';
const apiGetSurveyShownCount = '${apiPrefix}getSurveyShownCount';

/// Increments the surveyShownCount of the of the activeSurvey (apiSetActiveSurvey).
const String apiIncrementSurveyShownCount =
const apiIncrementSurveyShownCount =
'${apiPrefix}incrementSurveyShownCount';

const String lastReleaseNotesVersionPropertyName = 'lastReleaseNotesVersion';
const lastReleaseNotesVersionPropertyName = 'lastReleaseNotesVersion';

/// Returns the last DevTools version for which we have shown release notes.
const String apiGetLastReleaseNotesVersion =
const apiGetLastReleaseNotesVersion =
'${apiPrefix}getLastReleaseNotesVersion';

/// Sets the last DevTools version for which we have shown release notes.
const String apiSetLastReleaseNotesVersion =
const apiSetLastReleaseNotesVersion =
'${apiPrefix}setLastReleaseNotesVersion';

/// Returns the base app size file, if present.
const String apiGetBaseAppSizeFile = '${apiPrefix}getBaseAppSizeFile';
const apiGetBaseAppSizeFile = '${apiPrefix}getBaseAppSizeFile';

/// Returns the test app size file used for comparing two files in a diff, if
/// present.
const String apiGetTestAppSizeFile = '${apiPrefix}getTestAppSizeFile';
const apiGetTestAppSizeFile = '${apiPrefix}getTestAppSizeFile';

const String baseAppSizeFilePropertyName = 'appSizeBase';
const baseAppSizeFilePropertyName = 'appSizeBase';

const String testAppSizeFilePropertyName = 'appSizeTest';
const testAppSizeFilePropertyName = 'appSizeTest';

/// Serves any available extensions and returns a list of their configurations
/// to DevTools.
const apiServeAvailableExtensions =
'${apiPrefix}serveAvailableExtensions';

/// The property name for the query parameter passed along with
/// [apiServeAvailableExtensions] requests to the server.
const extensionRootPathPropertyName = 'rootPath';

/// The property name for the response that the server sends back upon
/// receiving a [apiServeAvailableExtensions] request.
const extensionsResultPropertyName = 'extensions';
Loading

0 comments on commit 5d062a7

Please sign in to comment.