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 a server endpoint for serving devtools extensions #6094

Merged
merged 6 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
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(
bkonyi marked this conversation as resolved.
Show resolved Hide resolved
materialIconCodePoint,
fontFamily: 'MaterialIcons',
);
}
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?>>();
bkonyi marked this conversation as resolved.
Show resolved Hide resolved
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';
kenzieschmoll marked this conversation as resolved.
Show resolved Hide resolved

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