diff options
Diffstat (limited to 'devtools/client/aboutdebugging/components/workers/panel.js')
-rw-r--r-- | devtools/client/aboutdebugging/components/workers/panel.js | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/components/workers/panel.js b/devtools/client/aboutdebugging/components/workers/panel.js new file mode 100644 index 000000000..b1bab2b99 --- /dev/null +++ b/devtools/client/aboutdebugging/components/workers/panel.js @@ -0,0 +1,193 @@ +/* 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/. */ +/* globals window */ +"use strict"; + +loader.lazyImporter(this, "PrivateBrowsingUtils", + "resource://gre/modules/PrivateBrowsingUtils.jsm"); + +const { Ci } = require("chrome"); +const { createClass, createFactory, DOM: dom, PropTypes } = + require("devtools/client/shared/vendor/react"); +const { getWorkerForms } = require("../../modules/worker"); +const Services = require("Services"); + +const PanelHeader = createFactory(require("../panel-header")); +const TargetList = createFactory(require("../target-list")); +const WorkerTarget = createFactory(require("./target")); +const ServiceWorkerTarget = createFactory(require("./service-worker-target")); + +loader.lazyImporter(this, "PrivateBrowsingUtils", + "resource://gre/modules/PrivateBrowsingUtils.jsm"); + +loader.lazyRequireGetter(this, "DebuggerClient", + "devtools/shared/client/main", true); + +const Strings = Services.strings.createBundle( + "chrome://devtools/locale/aboutdebugging.properties"); + +const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg"; +const MORE_INFO_URL = "https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging"; + +module.exports = createClass({ + displayName: "WorkersPanel", + + propTypes: { + client: PropTypes.instanceOf(DebuggerClient).isRequired, + id: PropTypes.string.isRequired + }, + + getInitialState() { + return { + workers: { + service: [], + shared: [], + other: [] + } + }; + }, + + componentDidMount() { + let client = this.props.client; + client.addListener("workerListChanged", this.update); + client.addListener("serviceWorkerRegistrationListChanged", this.update); + client.addListener("processListChanged", this.update); + client.addListener("registration-changed", this.update); + + this.update(); + }, + + componentWillUnmount() { + let client = this.props.client; + client.removeListener("processListChanged", this.update); + client.removeListener("serviceWorkerRegistrationListChanged", this.update); + client.removeListener("workerListChanged", this.update); + client.removeListener("registration-changed", this.update); + }, + + update() { + let workers = this.getInitialState().workers; + + getWorkerForms(this.props.client).then(forms => { + forms.registrations.forEach(form => { + workers.service.push({ + icon: WorkerIcon, + name: form.url, + url: form.url, + scope: form.scope, + registrationActor: form.actor, + active: form.active + }); + }); + + forms.workers.forEach(form => { + let worker = { + icon: WorkerIcon, + name: form.url, + url: form.url, + workerActor: form.actor + }; + switch (form.type) { + case Ci.nsIWorkerDebugger.TYPE_SERVICE: + let registration = this.getRegistrationForWorker(form, workers.service); + if (registration) { + // XXX: Race, sometimes a ServiceWorkerRegistrationInfo doesn't + // have a scriptSpec, but its associated WorkerDebugger does. + if (!registration.url) { + registration.name = registration.url = form.url; + } + registration.workerActor = form.actor; + } else { + // If a service worker registration could not be found, this means we are in + // e10s, and registrations are not forwarded to other processes until they + // reach the activated state. Augment the worker as a registration worker to + // display it in aboutdebugging. + worker.scope = form.scope; + worker.active = false; + workers.service.push(worker); + } + break; + case Ci.nsIWorkerDebugger.TYPE_SHARED: + workers.shared.push(worker); + break; + default: + workers.other.push(worker); + } + }); + + // XXX: Filter out the service worker registrations for which we couldn't + // find the scriptSpec. + workers.service = workers.service.filter(reg => !!reg.url); + + this.setState({ workers }); + }); + }, + + getRegistrationForWorker(form, registrations) { + for (let registration of registrations) { + if (registration.scope === form.scope) { + return registration; + } + } + return null; + }, + + render() { + let { client, id } = this.props; + let { workers } = this.state; + + let isWindowPrivate = PrivateBrowsingUtils.isContentWindowPrivate(window); + let isPrivateBrowsingMode = PrivateBrowsingUtils.permanentPrivateBrowsing; + let isServiceWorkerDisabled = !Services.prefs + .getBoolPref("dom.serviceWorkers.enabled"); + let errorMsg = isWindowPrivate || isPrivateBrowsingMode || + isServiceWorkerDisabled ? + dom.p({ className: "service-worker-disabled" }, + dom.div({ className: "warning" }), + Strings.GetStringFromName("configurationIsNotCompatible"), + " (", + dom.a({ href: MORE_INFO_URL, target: "_blank" }, + Strings.GetStringFromName("moreInfo")), + ")" + ) : ""; + + return dom.div({ + id: id + "-panel", + className: "panel", + role: "tabpanel", + "aria-labelledby": id + "-header" + }, + PanelHeader({ + id: id + "-header", + name: Strings.GetStringFromName("workers") + }), + dom.div({ id: "workers", className: "inverted-icons" }, + TargetList({ + client, + error: errorMsg, + id: "service-workers", + name: Strings.GetStringFromName("serviceWorkers"), + sort: true, + targetClass: ServiceWorkerTarget, + targets: workers.service + }), + TargetList({ + client, + id: "shared-workers", + name: Strings.GetStringFromName("sharedWorkers"), + sort: true, + targetClass: WorkerTarget, + targets: workers.shared + }), + TargetList({ + client, + id: "other-workers", + name: Strings.GetStringFromName("otherWorkers"), + sort: true, + targetClass: WorkerTarget, + targets: workers.other + }) + )); + } +}); |