Bug 1471795 - Part 15: Implement worker list. r?jdescottes, r?ladybenko
MozReview-Commit-ID: EIGrBTAHlwl
--- a/devtools/client/aboutdebugging-new/aboutdebugging.css
+++ b/devtools/client/aboutdebugging-new/aboutdebugging.css
@@ -6,15 +6,16 @@
@import "resource://devtools/client/themes/variables.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/App.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/RuntimeInfo.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/RuntimesPane.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetItem.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/DebugTargetList.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/ExtensionItem.css";
+@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/debugtarget/TemporaryExtensionInstaller.css";
@import "resource://devtools/client/aboutdebugging-new/src/components/runtime/ThisFirefoxItem.css";
#mount {
height: 100%;
width: 100%;
}
--- a/devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
+++ b/devtools/client/aboutdebugging-new/src/components/DebugTargetsPane.js
@@ -8,19 +8,21 @@ const { createFactory, PureComponent } =
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const Runtime = require("../runtimes/runtime");
const DebugTargetList = createFactory(require("./debugtarget/DebugTargetList"));
const ExtensionItem = createFactory(require("./debugtarget/ExtensionItem"));
const RuntimeInfo = createFactory(require("./RuntimeInfo"));
+const ServiceWorkerItem = createFactory(require("./debugtarget/ServiceWorkerItem"));
const TabItem = createFactory(require("./debugtarget/TabItem"));
const TemporaryExtensionInstaller =
createFactory(require("./debugtarget/TemporaryExtensionInstaller"));
+const WorkerItem = createFactory(require("./debugtarget/WorkerItem"));
class DebugTargetsPane extends PureComponent {
static get propTypes() {
return {
runtime: PropTypes.instanceOf(Runtime).isRequired,
};
}
@@ -28,18 +30,21 @@ class DebugTargetsPane extends PureCompo
super(props);
this.onExtensionsUpdated = this.onExtensionsUpdated.bind(this);
this.onTabsUpdated = this.onTabsUpdated.bind(this);
this.state = {
info: {},
installedExtensions: [],
+ otherWorkers: [],
tabs: [],
temporaryExtensions: [],
+ serviceWorkers: [],
+ sharedWorkers: [],
};
this.update(props.runtime);
}
componentDidUpdate(prevProps) {
if (prevProps.runtime !== this.props.runtime) {
const { runtime } = prevProps;
runtime.removeExtensionsUpdateListener(this.onExtensionsUpdated);
@@ -53,16 +58,17 @@ class DebugTargetsPane extends PureCompo
runtime.removeExtensionsUpdateListener(this.onExtensionsUpdated);
runtime.removeTabsUpdateListener(this.onTabsUpdated);
}
update(runtime) {
this.updateRuntimeInfo(runtime);
this.updateTabs(runtime);
this.updateExtensions(runtime);
+ this.updateWorkers(runtime);
runtime.addExtensionsUpdateListener(this.onExtensionsUpdated);
runtime.addTabsUpdateListener(this.onTabsUpdated);
}
async updateExtensions(runtime) {
const extensions = (await runtime.getExtensions()).filter(t => t.debuggable);
const installedExtensions = extensions.filter(t => !t.temporarilyInstalled);
@@ -76,31 +82,43 @@ class DebugTargetsPane extends PureCompo
}
async updateTabs(runtime) {
// Filter out closed tabs (represented as `null`).
const tabs = (await runtime.getTabs()).filter(t => !!t);
this.setState({ tabs });
}
+ async updateWorkers(runtime) {
+ const {
+ other: otherWorkers,
+ service: serviceWorkers,
+ shared: sharedWorkers,
+ } = await runtime.getWorkers();
+ this.setState({ otherWorkers, serviceWorkers, sharedWorkers });
+ }
+
onExtensionsUpdated() {
this.updateExtensions(this.props.runtime);
}
onTabsUpdated() {
this.updateTabs(this.props.runtime);
}
render() {
const { runtime } = this.props;
const {
info,
installedExtensions,
+ otherWorkers,
tabs,
temporaryExtensions,
+ serviceWorkers,
+ sharedWorkers,
} = this.state;
return dom.div(
{
className: "debug-targets-pane",
},
RuntimeInfo({ info }),
DebugTargetList({
@@ -119,14 +137,33 @@ class DebugTargetsPane extends PureCompo
title: "Extensions",
}),
DebugTargetList({
className: "debug-target-list--tabs",
debugTargetItemComponent: TabItem,
debugTargets: tabs,
runtime,
title: "Tabs",
+ }),
+ DebugTargetList({
+ className: "debug-target-list--service-workers",
+ debugTargetItemComponent: ServiceWorkerItem,
+ debugTargets: serviceWorkers,
+ runtime,
+ title: "Service Workers",
+ }),
+ DebugTargetList({
+ className: "debug-target-list--shared-workers",
+ debugTargetItemComponent: WorkerItem,
+ debugTargets: sharedWorkers,
+ title: "Shared Workers",
+ }),
+ DebugTargetList({
+ className: "debug-target-list--other-workers",
+ debugTargetItemComponent: WorkerItem,
+ debugTargets: otherWorkers,
+ title: "Other Workers",
})
);
}
}
module.exports = DebugTargetsPane;
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.css
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+.debug-target-item__info__detail__service-worker__info {
+ display: grid;
+ grid-template-columns: 100px 1fr;
+ margin-block-start: 4px;
+}
+
+.debug-target-item__info__detail__service-worker__info__label {
+}
+
+.debug-target-item__info__detail__service-worker__info__content {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.debug-target-item__info__detail__service-worker__status {
+ border-style: solid;
+ border-width: 1px;
+ box-sizing: border-box;
+ display: inline-block;
+ font-size: 10px;
+ margin-block-start: 6px;
+ min-width: 50px;
+ padding-block-start: 2px;
+ padding-block-end: 2px;
+ text-align: center;
+}
+
+.debug-target-item__info__detail__service-worker__status--running {
+ border-color: limegreen;
+ background-color: palegreen;
+}
+
+.debug-target-item__info__detail__service-worker__status--stopped {
+ border-color: grey;
+ background-color: lightgrey;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/ServiceWorkerItem.js
@@ -0,0 +1,159 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const WorkerItem = require("./WorkerItem");
+
+class ServiceWorkerItem extends WorkerItem {
+ constructor(props) {
+ super(props);
+ this.state = {
+ pushSubscription: null,
+ };
+ this.updateState(props);
+ }
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.runtime !== this.props.runtime ||
+ prevProps.debugTarget !== this.props.debugTarget) {
+ this.updateState(this.props);
+ }
+ }
+
+ getStatus() {
+ if (this.isActive() && this.isRunning()) {
+ return "running";
+ } else if (this.isActive()) {
+ return "stopped";
+ }
+ // We cannot get service worker registrations unless the registration is in
+ // ACTIVE state. Unable to know the actual state ("installing", "waiting"), we
+ // display a custom state "registering" for now. See Bug 1153292.
+ return "registering";
+ }
+
+ isRunning() {
+ const { debugTarget } = this.props;
+ // We know the target is running if it has a worker actor.
+ return !!debugTarget.workerTargetActor;
+ }
+
+ isActive() {
+ const { debugTarget } = this.props;
+ return debugTarget.active;
+ }
+
+ renderActionComponents() {
+ return null;
+ }
+
+ renderDetailComponents() {
+ return [
+ dom.div(
+ {
+ className: "debug-target-item__info__detail__service-worker__info",
+ },
+ this.renderFetch(),
+ this.renderScope(),
+ ),
+ this.renderStatus(),
+ ];
+ }
+
+ renderFetch() {
+ const { debugTarget } = this.props;
+ const fetch = debugTarget.fetch ? "Listening for fetch events."
+ : "Not listening for fetch events.";
+
+ return [
+ dom.dt(
+ {
+ className: "debug-target-item__info__detail__service-worker__info__label",
+ },
+ "Fetch"
+ ),
+ dom.dd(
+ {
+ className: "debug-target-item__info__detail__service-worker__info__content",
+ title: fetch,
+ },
+ fetch
+ ),
+ ];
+ }
+
+ renderPushService() {
+ const { pushSubscription } = this.state;
+
+ if (!pushSubscription) {
+ return null;
+ }
+
+ return [
+ dom.dt(
+ {
+ className: "debug-target-item__info__detail__service-worker__info__label",
+ },
+ "Push Service"
+ ),
+ dom.dd(
+ {
+ className: "debug-target-item__info__detail__service-worker__info__content",
+ title: pushSubscription.endpoint,
+ },
+ pushSubscription.endpoint
+ ),
+ ];
+ }
+
+ renderScope() {
+ const { debugTarget } = this.props;
+
+ return [
+ dom.dt(
+ {
+ className: "debug-target-item__info__detail__service-worker__info__label",
+ },
+ "Scope"
+ ),
+ dom.dd(
+ {
+ className: "debug-target-item__info__detail__service-worker__info__content",
+ title: debugTarget.scope,
+ },
+ debugTarget.scope
+ ),
+ ];
+ }
+
+ renderStatus() {
+ const status = this.getStatus();
+
+ return dom.div(
+ {
+ className: "debug-target-item__info__detail__service-worker__status " +
+ `debug-target-item__info__detail__service-worker__status--${ status }`,
+ },
+ status
+ );
+ }
+
+ async updateState({ debugTarget, runtime }) {
+ if (!debugTarget) {
+ // A valid registrationActor is needed to retrieve the push subscription.
+ return;
+ }
+
+ const { subscription } = await runtime.sendRequest({
+ to: debugTarget.registrationActor,
+ type: "getPushSubscription",
+ });
+ this.setState({ pushSubscription: subscription });
+ }
+}
+
+module.exports = ServiceWorkerItem;
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/WorkerItem.js
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const DebugTargetItem = require("./DebugTargetItem");
+
+class WorkerItem extends DebugTargetItem {
+ getIcon() {
+ return "chrome://devtools/skin/images/debugging-workers.svg";
+ }
+
+ getName() {
+ const { debugTarget } = this.props;
+ return debugTarget.name;
+ }
+
+ renderActionComponents() {
+ return null;
+ }
+
+ renderDetailComponents() {
+ return null;
+ }
+}
+
+module.exports = WorkerItem;
--- a/devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
+++ b/devtools/client/aboutdebugging-new/src/components/debugtarget/moz.build
@@ -4,12 +4,15 @@
DevToolsModules(
'DebugTargetItem.css',
'DebugTargetItem.js',
'DebugTargetList.css',
'DebugTargetList.js',
'ExtensionItem.css',
'ExtensionItem.js',
+ 'ServiceWorkerItem.css',
+ 'ServiceWorkerItem.js',
'TabItem.js',
'TemporaryExtensionInstaller.css',
- 'TemporaryExtensionInstaller.js'
+ 'TemporaryExtensionInstaller.js',
+ 'WorkerItem.js'
)
--- a/devtools/client/aboutdebugging-new/src/runtimes/runtime.js
+++ b/devtools/client/aboutdebugging-new/src/runtimes/runtime.js
@@ -81,16 +81,25 @@ class Runtime {
* Subclass should override this method.
* @return {Array}
*/
async getTabs() {
throw new Error("Subclass of Runtime should override getTabs()");
}
/**
+ * Return workers on this runtime.
+ * Subclass should override this method.
+ * @return {Array}
+ */
+ async getWorkers() {
+ throw new Error("Subclass of Runtime should override getWorkers()");
+ }
+
+ /**
* Inspect the provided extension target which can get by getExtensions().
* Subclass should override this method.
* @param {Object} - debug target
*/
async inspectExtension(_) {
throw new Error("Subclass of Runtime should override inspectExtension()");
}
--- a/devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
+++ b/devtools/client/aboutdebugging-new/src/runtimes/this-firefox.js
@@ -67,16 +67,20 @@ class ThisFirefox extends Runtime {
};
}
async getTabs() {
const { tabs } = await this.client.listTabs({ favicons: true });
return tabs;
}
+ async getWorkers() {
+ return this.client.mainRoot.listAllWorkers();
+ }
+
async inspectExtension(debugTarget) {
// Close previous addon debugging toolbox.
if (this.browserToolboxProcess) {
this.browserToolboxProcess.close();
}
this.browserToolboxProcess = BrowserToolboxProcess.init({
addonID: debugTarget.id,