summaryrefslogtreecommitdiffstats
path: root/devtools/client/aboutdebugging/src/components/App.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/aboutdebugging/src/components/App.js')
-rw-r--r--devtools/client/aboutdebugging/src/components/App.js213
1 files changed, 213 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/src/components/App.js b/devtools/client/aboutdebugging/src/components/App.js
new file mode 100644
index 0000000000..7bdf3eb0c5
--- /dev/null
+++ b/devtools/client/aboutdebugging/src/components/App.js
@@ -0,0 +1,213 @@
+/* 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 {
+ connect,
+} = require("resource://devtools/client/shared/vendor/react-redux.js");
+const {
+ createFactory,
+ PureComponent,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+
+const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js");
+const Localized = createFactory(FluentReact.Localized);
+
+const Route = createFactory(
+ require("resource://devtools/client/shared/vendor/react-router-dom.js").Route
+);
+const Switch = createFactory(
+ require("resource://devtools/client/shared/vendor/react-router-dom.js").Switch
+);
+const Redirect = createFactory(
+ require("resource://devtools/client/shared/vendor/react-router-dom.js")
+ .Redirect
+);
+
+const Types = require("resource://devtools/client/aboutdebugging/src/types/index.js");
+const {
+ PAGE_TYPES,
+ RUNTIMES,
+} = require("resource://devtools/client/aboutdebugging/src/constants.js");
+
+const ConnectPage = createFactory(
+ require("resource://devtools/client/aboutdebugging/src/components/connect/ConnectPage.js")
+);
+const RuntimePage = createFactory(
+ require("resource://devtools/client/aboutdebugging/src/components/RuntimePage.js")
+);
+const Sidebar = createFactory(
+ require("resource://devtools/client/aboutdebugging/src/components/sidebar/Sidebar.js")
+);
+
+class App extends PureComponent {
+ static get propTypes() {
+ return {
+ adbAddonStatus: Types.adbAddonStatus,
+ // The "dispatch" helper is forwarded to the App component via connect.
+ // From that point, components are responsible for forwarding the dispatch
+ // property to all components who need to dispatch actions.
+ dispatch: PropTypes.func.isRequired,
+ // getString prop is injected by the withLocalization wrapper
+ getString: PropTypes.func.isRequired,
+ isAdbReady: PropTypes.bool.isRequired,
+ isScanningUsb: PropTypes.bool.isRequired,
+ networkLocations: PropTypes.arrayOf(Types.location).isRequired,
+ networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
+ selectedPage: Types.page,
+ selectedRuntimeId: PropTypes.string,
+ usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
+ };
+ }
+
+ componentDidUpdate() {
+ this.updateTitle();
+ }
+
+ updateTitle() {
+ const { getString, selectedPage, selectedRuntimeId } = this.props;
+
+ const pageTitle =
+ selectedPage === PAGE_TYPES.RUNTIME
+ ? getString("about-debugging-page-title-runtime-page", {
+ selectedRuntimeId,
+ })
+ : getString("about-debugging-page-title-setup-page");
+
+ document.title = pageTitle;
+ }
+
+ renderConnect() {
+ const { adbAddonStatus, dispatch, networkLocations } = this.props;
+
+ return ConnectPage({
+ adbAddonStatus,
+ dispatch,
+ networkLocations,
+ });
+ }
+
+ // The `match` object here is passed automatically by the Route object.
+ // We are using it to read the route path.
+ // See react-router docs:
+ // https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/match.md
+ renderRuntime({ match }) {
+ const isRuntimeAvailable = id => {
+ const runtimes = [
+ ...this.props.networkRuntimes,
+ ...this.props.usbRuntimes,
+ ];
+ const runtime = runtimes.find(x => x.id === id);
+ return runtime?.runtimeDetails;
+ };
+
+ const { dispatch } = this.props;
+
+ let runtimeId = match.params.runtimeId || RUNTIMES.THIS_FIREFOX;
+ if (match.params.runtimeId !== RUNTIMES.THIS_FIREFOX) {
+ const rawId = decodeURIComponent(match.params.runtimeId);
+ if (isRuntimeAvailable(rawId)) {
+ runtimeId = rawId;
+ } else {
+ // Also redirect to "This Firefox" if runtime is not found
+ return Redirect({ to: `/runtime/${RUNTIMES.THIS_FIREFOX}` });
+ }
+ }
+
+ // we need to pass a key so the component updates when we want to showcase
+ // a different runtime
+ return RuntimePage({ dispatch, key: runtimeId, runtimeId });
+ }
+
+ renderRoutes() {
+ return Switch(
+ {},
+ Route({
+ path: "/setup",
+ render: () => this.renderConnect(),
+ }),
+ Route({
+ path: "/runtime/:runtimeId",
+ render: routeProps => this.renderRuntime(routeProps),
+ }),
+ // default route when there's no match which includes "/"
+ // TODO: the url does not match "/" means invalid URL,
+ // in this case maybe we'd like to do something else than a redirect.
+ // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1509897
+ Route({
+ render: routeProps => {
+ const { pathname } = routeProps.location;
+ // The old about:debugging supported the following routes:
+ // about:debugging#workers, about:debugging#addons and about:debugging#tabs.
+ // Such links can still be found in external documentation pages.
+ // We redirect to This Firefox rather than the Setup Page here.
+ if (
+ pathname === "/workers" ||
+ pathname === "/addons" ||
+ pathname === "/tabs"
+ ) {
+ return Redirect({ to: `/runtime/${RUNTIMES.THIS_FIREFOX}` });
+ }
+ return Redirect({ to: "/setup" });
+ },
+ })
+ );
+ }
+
+ render() {
+ const {
+ adbAddonStatus,
+ dispatch,
+ isAdbReady,
+ isScanningUsb,
+ networkRuntimes,
+ selectedPage,
+ selectedRuntimeId,
+ usbRuntimes,
+ } = this.props;
+
+ return Localized(
+ {},
+ dom.div(
+ { className: "app" },
+ Sidebar({
+ adbAddonStatus,
+ className: "app__sidebar",
+ dispatch,
+ isAdbReady,
+ isScanningUsb,
+ networkRuntimes,
+ selectedPage,
+ selectedRuntimeId,
+ usbRuntimes,
+ }),
+ dom.main({ className: "app__content" }, this.renderRoutes())
+ )
+ );
+ }
+}
+
+const mapStateToProps = state => {
+ return {
+ adbAddonStatus: state.ui.adbAddonStatus,
+ isAdbReady: state.ui.isAdbReady,
+ isScanningUsb: state.ui.isScanningUsb,
+ networkLocations: state.ui.networkLocations,
+ networkRuntimes: state.runtimes.networkRuntimes,
+ selectedPage: state.ui.selectedPage,
+ selectedRuntimeId: state.runtimes.selectedRuntimeId,
+ usbRuntimes: state.runtimes.usbRuntimes,
+ };
+};
+
+const mapDispatchToProps = dispatch => ({
+ dispatch,
+});
+
+module.exports = FluentReact.withLocalization(
+ connect(mapStateToProps, mapDispatchToProps)(App)
+);