summaryrefslogtreecommitdiffstats
path: root/devtools/client/application/src/components/service-workers/Worker.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--devtools/client/application/src/components/service-workers/Worker.js225
1 files changed, 225 insertions, 0 deletions
diff --git a/devtools/client/application/src/components/service-workers/Worker.js b/devtools/client/application/src/components/service-workers/Worker.js
new file mode 100644
index 0000000000..bc95e084a9
--- /dev/null
+++ b/devtools/client/application/src/components/service-workers/Worker.js
@@ -0,0 +1,225 @@
+/* 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 {
+ createFactory,
+ PureComponent,
+} = require("resource://devtools/client/shared/vendor/react.js");
+
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+const {
+ connect,
+} = require("resource://devtools/client/shared/vendor/react-redux.js");
+
+const {
+ a,
+ img,
+ p,
+ section,
+ span,
+} = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+
+const {
+ getUnicodeUrlPath,
+} = require("resource://devtools/client/shared/unicode-url.js");
+
+const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js");
+const Localized = createFactory(FluentReact.Localized);
+const {
+ l10n,
+} = require("resource://devtools/client/application/src/modules/l10n.js");
+
+const {
+ services,
+} = require("resource://devtools/client/application/src/modules/application-services.js");
+const Types = require("resource://devtools/client/application/src/types/index.js");
+
+const {
+ startWorker,
+} = require("resource://devtools/client/application/src/actions/workers.js");
+
+const UIButton = createFactory(
+ require("resource://devtools/client/application/src/components/ui/UIButton.js")
+);
+
+/**
+ * This component is dedicated to display a worker, more accurately a service worker, in
+ * the list of workers displayed in the application panel. It displays information about
+ * the worker as well as action links and buttons to interact with the worker (e.g. debug,
+ * unregister, update etc...).
+ */
+class Worker extends PureComponent {
+ static get propTypes() {
+ return {
+ isDebugEnabled: PropTypes.bool.isRequired,
+ worker: PropTypes.shape(Types.worker).isRequired,
+ // this prop get automatically injected via `connect`
+ dispatch: PropTypes.func.isRequired,
+ };
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.debug = this.debug.bind(this);
+ this.viewSource = this.viewSource.bind(this);
+ this.start = this.start.bind(this);
+ }
+
+ debug() {
+ if (!this.isRunning()) {
+ console.log("Service workers cannot be debugged if they are not running");
+ return;
+ }
+
+ services.openWorkerInDebugger(this.props.worker.workerDescriptorFront);
+ }
+
+ viewSource() {
+ if (!this.isRunning()) {
+ console.log(
+ "Service workers cannot be inspected if they are not running"
+ );
+ return;
+ }
+
+ services.viewWorkerSource(this.props.worker.workerDescriptorFront);
+ }
+
+ start() {
+ if (!this.isActive() || this.isRunning()) {
+ console.log("Running or inactive service workers cannot be started");
+ return;
+ }
+
+ this.props.dispatch(startWorker(this.props.worker));
+ }
+
+ isRunning() {
+ // We know the worker is running if it has a worker actor.
+ return !!this.props.worker.workerDescriptorFront;
+ }
+
+ isActive() {
+ return this.props.worker.state === Ci.nsIServiceWorkerInfo.STATE_ACTIVATED;
+ }
+
+ getLocalizedStatus() {
+ if (this.isActive() && this.isRunning()) {
+ return l10n.getString("serviceworker-worker-status-running");
+ } else if (this.isActive()) {
+ return l10n.getString("serviceworker-worker-status-stopped");
+ }
+ // NOTE: this is already localized by the service worker front
+ // (strings are in debugger.properties)
+ return this.props.worker.stateText;
+ }
+
+ getClassNameForStatus(baseClass) {
+ const { state } = this.props.worker;
+
+ switch (state) {
+ case Ci.nsIServiceWorkerInfo.STATE_PARSED:
+ case Ci.nsIServiceWorkerInfo.STATE_INSTALLING:
+ return "worker__status--installing";
+ case Ci.nsIServiceWorkerInfo.STATE_INSTALLED:
+ case Ci.nsIServiceWorkerInfo.STATE_ACTIVATING:
+ return "worker__status--waiting";
+ case Ci.nsIServiceWorkerInfo.STATE_ACTIVATED:
+ return "worker__status--active";
+ }
+
+ return "worker__status--default";
+ }
+
+ formatSource(source) {
+ const parts = source.split("/");
+ return getUnicodeUrlPath(parts[parts.length - 1]);
+ }
+
+ renderInspectLink(url) {
+ // avoid rendering the inspect link if sw is not running
+ const isDisabled = !this.isRunning();
+ // view source instead of debugging when debugging sw is not available
+ const callbackFn = this.props.isDebugEnabled ? this.debug : this.viewSource;
+
+ const sourceUrl = span(
+ { className: "js-source-url" },
+ this.formatSource(url)
+ );
+
+ return isDisabled
+ ? sourceUrl
+ : a(
+ {
+ onClick: callbackFn,
+ title: url,
+ href: "#",
+ className: "js-inspect-link",
+ },
+ sourceUrl,
+ "\u00A0", //  
+ Localized(
+ {
+ id: "serviceworker-worker-inspect-icon",
+ attrs: {
+ alt: true,
+ },
+ },
+ img({
+ src: "chrome://devtools/skin/images/application-debug.svg",
+ })
+ )
+ );
+ }
+
+ renderStartButton() {
+ // avoid rendering the button at all for workers that are either running,
+ // or in a state that prevents them from starting (like waiting)
+ if (this.isRunning() || !this.isActive()) {
+ return null;
+ }
+
+ return Localized(
+ { id: "serviceworker-worker-start3" },
+ UIButton({
+ onClick: this.start,
+ className: `js-start-button`,
+ size: "micro",
+ })
+ );
+ }
+
+ render() {
+ const { worker } = this.props;
+ const statusText = this.getLocalizedStatus();
+ const statusClassName = this.getClassNameForStatus();
+
+ return section(
+ { className: "worker js-sw-worker" },
+ p(
+ { className: "worker__icon" },
+ img({
+ className: "worker__icon-image",
+ src: "chrome://devtools/skin/images/debugging-workers.svg",
+ })
+ ),
+ p({ className: "worker__source" }, this.renderInspectLink(worker.url)),
+ p(
+ { className: "worker__misc" },
+ span(
+ { className: `js-worker-status worker__status ${statusClassName}` },
+ statusText
+ ),
+ " ",
+ this.renderStartButton()
+ )
+ );
+ }
+}
+
+const mapDispatchToProps = dispatch => ({ dispatch });
+module.exports = connect(mapDispatchToProps)(Worker);