Bug 1425347 - Hide system add-ons by default in about:debugging r=jdescottes
authorMark Striemer <mstriemer@mozilla.com>
Mon, 28 May 2018 15:33:26 -0500
changeset 427372 74538c63a6a9a9d5be34a7ea2699acfd57465cae
parent 427371 6e38a0f11e038dc80c4a58eef65652d44311eda0
child 427373 7f73954c5633e0b9ddf209cd4f92e710f8bed63c
push id34303
push usertoros@mozilla.com
push dateFri, 20 Jul 2018 09:55:38 +0000
treeherdermozilla-central@47f713574cb2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1425347
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1425347 - Hide system add-ons by default in about:debugging r=jdescottes MozReview-Commit-ID: 4bhF6Zxsn6w
devtools/client/aboutdebugging/components/addons/Panel.js
devtools/client/aboutdebugging/test/browser_addons_debug_info.js
devtools/client/locales/en-US/aboutdebugging.properties
devtools/client/preferences/devtools-client.js
devtools/server/actors/addon/webextension.js
devtools/server/actors/targets/addon.js
--- a/devtools/client/aboutdebugging/components/addons/Panel.js
+++ b/devtools/client/aboutdebugging/components/addons/Panel.js
@@ -20,16 +20,17 @@ loader.lazyRequireGetter(this, "Debugger
   "devtools/shared/client/debugger-client", true);
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const ExtensionIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
 const CHROME_ENABLED_PREF = "devtools.chrome.enabled";
 const REMOTE_ENABLED_PREF = "devtools.debugger.remote-enabled";
+const SYSTEM_ENABLED_PREF = "devtools.aboutdebugging.showSystemAddons";
 const WEB_EXT_URL = "https://developer.mozilla.org/Add-ons" +
                     "/WebExtensions/Getting_started_with_web-ext";
 
 class AddonsPanel extends Component {
   static get propTypes() {
     return {
       client: PropTypes.instanceOf(DebuggerClient).isRequired,
       connect: PropTypes.object,
@@ -38,19 +39,21 @@ class AddonsPanel extends Component {
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
       extensions: [],
       debugDisabled: false,
+      showSystemAddons: false,
     };
 
     this.updateDebugStatus = this.updateDebugStatus.bind(this);
+    this.updateShowSystemStatus = this.updateShowSystemStatus.bind(this);
     this.updateAddonsList = this.updateAddonsList.bind(this);
     this.onInstalled = this.onInstalled.bind(this);
     this.onUninstalled = this.onUninstalled.bind(this);
     this.onEnabled = this.onEnabled.bind(this);
     this.onDisabled = this.onDisabled.bind(this);
   }
 
   componentDidMount() {
@@ -58,49 +61,60 @@ class AddonsPanel extends Component {
     // Listen to startup since that's when errors and warnings
     // get populated on the extension.
     Management.on("startup", this.updateAddonsList);
 
     Services.prefs.addObserver(CHROME_ENABLED_PREF,
       this.updateDebugStatus);
     Services.prefs.addObserver(REMOTE_ENABLED_PREF,
       this.updateDebugStatus);
+    Services.prefs.addObserver(SYSTEM_ENABLED_PREF,
+      this.updateShowSystemStatus);
 
     this.updateDebugStatus();
+    this.updateShowSystemStatus();
     this.updateAddonsList();
   }
 
   componentWillUnmount() {
     AddonManager.removeAddonListener(this);
     Management.off("startup", this.updateAddonsList);
 
     Services.prefs.removeObserver(CHROME_ENABLED_PREF,
       this.updateDebugStatus);
     Services.prefs.removeObserver(REMOTE_ENABLED_PREF,
       this.updateDebugStatus);
+    Services.prefs.removeObserver(SYSTEM_ENABLED_PREF,
+      this.updateShowSystemStatus);
   }
 
   updateDebugStatus() {
     const debugDisabled =
       !Services.prefs.getBoolPref(CHROME_ENABLED_PREF) ||
       !Services.prefs.getBoolPref(REMOTE_ENABLED_PREF);
 
     this.setState({ debugDisabled });
   }
 
+  updateShowSystemStatus() {
+    const showSystemAddons = Services.prefs.getBoolPref(SYSTEM_ENABLED_PREF, false);
+    this.setState({ showSystemAddons });
+  }
+
   updateAddonsList() {
     this.props.client.listAddons()
       .then(({addons}) => {
         const extensions = addons.filter(addon => addon.debuggable).map(addon => {
           return {
             addonTargetActor: addon.actor,
             addonID: addon.id,
             // Forward the whole addon actor form for potential remote debugging.
             form: addon,
             icon: addon.iconURL || ExtensionIcon,
+            isSystem: addon.isSystem,
             manifestURL: addon.manifestURL,
             name: addon.name,
             temporarilyInstalled: addon.temporarilyInstalled,
             url: addon.url,
             warnings: addon.warnings,
           };
         });
 
@@ -135,23 +149,26 @@ class AddonsPanel extends Component {
    * Mandatory callback as AddonManager listener.
    */
   onDisabled() {
     this.updateAddonsList();
   }
 
   render() {
     const { client, connect, id } = this.props;
-    const { debugDisabled, extensions: targets } = this.state;
+    const { debugDisabled, extensions: targets, showSystemAddons } = this.state;
     const installedName = Strings.GetStringFromName("extensions");
     const temporaryName = Strings.GetStringFromName("temporaryExtensions");
+    const systemName = Strings.GetStringFromName("systemExtensions");
     const targetClass = AddonTarget;
 
-    const installedTargets = targets.filter((target) => !target.temporarilyInstalled);
+    const installedTargets = targets.filter(
+      (target) => !target.isSystem && !target.temporarilyInstalled);
     const temporaryTargets = targets.filter((target) => target.temporarilyInstalled);
+    const systemTargets = showSystemAddons && targets.filter((target) => target.isSystem);
 
     return dom.div({
       id: id + "-panel",
       className: "panel",
       role: "tabpanel",
       "aria-labelledby": id + "-header"
     },
     PanelHeader({
@@ -186,13 +203,27 @@ class AddonsPanel extends Component {
         name: installedName,
         targets: installedTargets,
         client,
         connect,
         debugDisabled,
         targetClass,
         sort: true
       })
-    ));
+    ),
+    showSystemAddons ?
+      dom.div({ id: "system-addons" },
+        TargetList({
+          id: "system-extensions",
+          name: systemName,
+          targets: systemTargets,
+          client,
+          connect,
+          debugDisabled,
+          targetClass,
+          sort: true
+        })
+      ) : null,
+    );
   }
 }
 
 module.exports = AddonsPanel;
--- a/devtools/client/aboutdebugging/test/browser_addons_debug_info.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_debug_info.js
@@ -1,11 +1,14 @@
 "use strict";
 
+const { Preferences } = ChromeUtils.import("resource://gre/modules/Preferences.jsm", {});
+
 const UUID_REGEX = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;
+const SHOW_SYSTEM_ADDONS_PREF = "devtools.aboutdebugging.showSystemAddons";
 
 function testFilePath(container, expectedFilePath) {
   // Verify that the path to the install location is shown next to its label.
   const filePath = container.querySelector(".file-path");
   ok(filePath, "file path is in DOM");
   ok(filePath.textContent.endsWith(expectedFilePath), "file path is set correctly");
   is(filePath.previousElementSibling.textContent, "Location", "file path has label");
 }
@@ -114,8 +117,31 @@ add_task(async function testUnknownManif
      "the message is helpful");
   ok(messages[0].classList.contains("addon-target-warning-message"),
      "the message is a warning");
 
   await uninstallAddon({document, id: addonId, name: addonName});
 
   await closeAboutDebugging(tab);
 });
+
+add_task(async function testSystemAddonsHidden() {
+  await pushPref(SHOW_SYSTEM_ADDONS_PREF, false);
+
+  const { document } = await openAboutDebugging("addons");
+  const systemAddonsShown = () => !!document.getElementById("system-extensions");
+
+  await waitForInitialAddonList(document);
+
+  ok(!systemAddonsShown(), "System extensions are hidden");
+
+  Preferences.set(SHOW_SYSTEM_ADDONS_PREF, true);
+
+  await waitUntil(systemAddonsShown);
+
+  ok(systemAddonsShown(), "System extensions are now shown");
+
+  Preferences.set(SHOW_SYSTEM_ADDONS_PREF, false);
+
+  await waitUntil(() => !systemAddonsShown());
+
+  ok(!systemAddonsShown(), "System extensions are hidden again");
+});
--- a/devtools/client/locales/en-US/aboutdebugging.properties
+++ b/devtools/client/locales/en-US/aboutdebugging.properties
@@ -71,16 +71,20 @@ retryTemporaryInstall = Retry
 # LOCALIZATION NOTE (extensions):
 # This string is displayed as a header above the list of loaded add-ons.
 extensions = Extensions
 
 # LOCALIZATION NOTE (temporaryExtensions):
 # This string is displayed as a header above the list of temporarily loaded add-ons.
 temporaryExtensions = Temporary Extensions
 
+# LOCALIZATION NOTE (systemExtensions):
+# This string is displayed as a header above the list of system add-ons.
+systemExtensions = System Extensions
+
 # LOCALIZATION NOTE (internalUUID):
 # This string is displayed as a label for the internal UUID of an extension.
 # The UUID is generated for this profile on install.
 internalUUID = Internal UUID
 
 # LOCALIZATION NOTE (extensionID):
 # This string is displayed as a label for the ID of an extension. This is not the same as the internal UUID.
 extensionID = Extension ID
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -307,8 +307,15 @@ pref("devtools.editor.enableCodeFolding"
 pref("devtools.editor.autocomplete", true);
 
 // Whether to reload when touch simulation is toggled
 pref("devtools.responsive.reloadConditions.touchSimulation", false);
 // Whether to reload when user agent is changed
 pref("devtools.responsive.reloadConditions.userAgent", false);
 // Whether to show the notification about reloading to apply emulation
 pref("devtools.responsive.reloadNotification.enabled", true);
+
+// about:debugging: only show system add-ons in local builds by default.
+#ifdef MOZILLA_OFFICIAL
+  pref("devtools.aboutdebugging.showSystemAddons", false);
+#else
+  pref("devtools.aboutdebugging.showSystemAddons", true);
+#endif
--- a/devtools/server/actors/addon/webextension.js
+++ b/devtools/server/actors/addon/webextension.js
@@ -74,16 +74,17 @@ const WebExtensionActor = protocol.Actor
   form() {
     const policy = ExtensionParent.WebExtensionPolicy.getByID(this.id);
     return {
       actor: this.actorID,
       id: this.id,
       name: this.addon.name,
       url: this.addon.sourceURI ? this.addon.sourceURI.spec : undefined,
       iconURL: this.addon.iconURL,
+      isSystem: this.addon.isSystem,
       debuggable: this.addon.isDebuggable,
       temporarilyInstalled: this.addon.temporarilyInstalled,
       type: this.addon.type,
       isWebExtension: this.addon.isWebExtension,
       isAPIExtension: this.addon.isAPIExtension,
       manifestURL: policy && policy.getURL("manifest.json"),
       warnings: ExtensionParent.DebugUtils.getExtensionManifestWarnings(this.id),
     };
--- a/devtools/server/actors/targets/addon.js
+++ b/devtools/server/actors/targets/addon.js
@@ -82,16 +82,17 @@ AddonTargetActor.prototype = {
     }
 
     return {
       actor: this.actorID,
       id: this.id,
       name: this._addon.name,
       url: this.url,
       iconURL: this._addon.iconURL,
+      isSystem: this._addon.isSystem,
       debuggable: this._addon.isDebuggable,
       temporarilyInstalled: this._addon.temporarilyInstalled,
       type: this._addon.type,
       isWebExtension: this._addon.isWebExtension,
       isAPIExtension: this._addon.isAPIExtension,
       consoleActor: this._consoleActor.actorID,
 
       traits: {