Bug 1258353 - Refactor devtools react components. r=janx
authorBenoit Chabod <be.chabod@gmail.com>
Tue, 17 May 2016 11:55:49 -0700
changeset 322194 0033e0f0a351b5ba2ff61859e511e76e87e43386
parent 322193 f27d4b4d5154565d494bee3b793df8249957769f
child 322195 b02b83d3af40bda57d04c1e8ce91054a35b0aeb2
push id9671
push userraliiev@mozilla.com
push dateMon, 06 Jun 2016 20:27:52 +0000
treeherdermozilla-aurora@cea65ca3d0bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanx
bugs1258353
milestone49.0a1
Bug 1258353 - Refactor devtools react components. r=janx
devtools/.eslintrc
devtools/client/dom/content/components/dom-tree.js
devtools/client/dom/content/components/main-frame.js
devtools/client/dom/content/components/main-toolbar.js
devtools/client/dom/content/components/search-box.js
devtools/client/jsonview/components/headers-panel.js
devtools/client/jsonview/components/headers.js
devtools/client/jsonview/components/json-panel.js
devtools/client/jsonview/components/main-tabbed-area.js
devtools/client/jsonview/components/reps/tabs.js
devtools/client/jsonview/components/reps/toolbar.js
devtools/client/jsonview/components/search-box.js
devtools/client/jsonview/components/text-panel.js
devtools/client/responsive.html/app.js
devtools/client/responsive.html/components/browser.js
devtools/client/responsive.html/components/device-modal.js
devtools/client/responsive.html/components/device-selector.js
devtools/client/responsive.html/components/global-toolbar.js
devtools/client/responsive.html/components/resizable-viewport.js
devtools/client/responsive.html/components/viewport-dimension.js
devtools/client/responsive.html/components/viewport-toolbar.js
devtools/client/responsive.html/components/viewport.js
devtools/client/responsive.html/components/viewports.js
--- a/devtools/.eslintrc
+++ b/devtools/.eslintrc
@@ -37,17 +37,17 @@
     "react/no-danger": 2,
     "react/no-did-mount-set-state": 2,
     "react/no-did-update-set-state": 2,
     "react/no-direct-mutation-state": 2,
     "react/no-unknown-property": 2,
     "react/prefer-es6-class": [1, "never"],
     // Disabled temporarily until errors are fixed.
     "react/prop-types": 0,
-    "react/sort-comp": [1, {
+    "react/sort-comp": [2, {
       order: [
         "lifecycle",
         "everything-else",
         "render"
       ],
       groups: {
         lifecycle: [
           "displayName",
--- a/devtools/client/dom/content/components/dom-tree.js
+++ b/devtools/client/dom/content/components/dom-tree.js
@@ -21,25 +21,25 @@ const { DomDecorator } = require("../dom
 
 // Shortcuts
 const PropTypes = React.PropTypes;
 
 /**
  * Renders DOM panel tree.
  */
 var DomTree = React.createClass({
+  displayName: "DomTree",
+
   propTypes: {
     object: PropTypes.any,
     filter: PropTypes.string,
     dispatch: PropTypes.func.isRequired,
     grips: PropTypes.object,
   },
 
-  displayName: "DomTree",
-
   /**
    * Filter DOM properties. Return true if the object
    * should be visible in the tree.
    */
   onFilter: function (object) {
     if (!this.props.filter) {
       return true;
     }
--- a/devtools/client/dom/content/components/main-frame.js
+++ b/devtools/client/dom/content/components/main-frame.js
@@ -17,24 +17,24 @@ const MainToolbar = React.createFactory(
 const { div } = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * Renders basic layout of the DOM panel. The DOM panel cotent consists
  * from two main parts: toolbar and tree.
  */
 var MainFrame = React.createClass({
+  displayName: "MainFrame",
+
   propTypes: {
     object: PropTypes.any,
     filter: PropTypes.string,
     dispatch: PropTypes.func.isRequired,
   },
 
-  displayName: "MainFrame",
-
   /**
    * Render DOM panel content
    */
   render: function () {
     return (
       div({className: "mainFrame"},
         MainToolbar({
           dispatch: this.props.dispatch,
--- a/devtools/client/dom/content/components/main-toolbar.js
+++ b/devtools/client/dom/content/components/main-toolbar.js
@@ -23,23 +23,23 @@ const { setVisibilityFilter } = require(
 // Shortcuts
 const PropTypes = React.PropTypes;
 
 /**
  * This template is responsible for rendering a toolbar
  * within the 'Headers' panel.
  */
 var MainToolbar = React.createClass({
+  displayName: "MainToolbar",
+
   propTypes: {
     object: PropTypes.any.isRequired,
     dispatch: PropTypes.func.isRequired,
   },
 
-  displayName: "MainToolbar",
-
   onRefresh: function () {
     this.props.dispatch(fetchProperties(this.props.object));
   },
 
   onSearch: function (value) {
     this.props.dispatch(setVisibilityFilter(value));
   },
 
--- a/devtools/client/dom/content/components/search-box.js
+++ b/devtools/client/dom/content/components/search-box.js
@@ -16,22 +16,22 @@ const searchDelay = 250;
 const { input } = React.DOM;
 const PropTypes = React.PropTypes;
 
 /**
  * This object represents a search box located at the
  * top right corner of the application.
  */
 var SearchBox = React.createClass({
+  displayName: "SearchBox",
+
   propTypes: {
     onSearch: PropTypes.func,
   },
 
-  displayName: "SearchBox",
-
   componentWillUnmount: function () {
     // Clean up an existing timeout.
     if (this.searchTimeout) {
       window.clearTimeout(this.searchTimeout);
     }
   },
 
   onSearch: function (event) {
--- a/devtools/client/jsonview/components/headers-panel.js
+++ b/devtools/client/jsonview/components/headers-panel.js
@@ -14,23 +14,23 @@ define(function (require, exports, modul
 
   const { div } = dom;
 
   /**
    * This template represents the 'Headers' panel
    * s responsible for rendering its content.
    */
   let HeadersPanel = createClass({
+    displayName: "HeadersPanel",
+
     propTypes: {
       actions: PropTypes.object,
       data: PropTypes.object,
     },
 
-    displayName: "HeadersPanel",
-
     getInitialState: function () {
       return {
         data: {}
       };
     },
 
     render: function () {
       let data = this.props.data;
@@ -46,22 +46,22 @@ define(function (require, exports, modul
     }
   });
 
   /**
    * This template is responsible for rendering a toolbar
    * within the 'Headers' panel.
    */
   let HeadersToolbar = createFactory(createClass({
+    displayName: "HeadersToolbar",
+
     propTypes: {
       actions: PropTypes.object,
     },
 
-    displayName: "HeadersToolbar",
-
     // Commands
 
     onCopy: function (event) {
       this.props.actions.onCopyHeaders();
     },
 
     render: function () {
       return (
--- a/devtools/client/jsonview/components/headers.js
+++ b/devtools/client/jsonview/components/headers.js
@@ -12,22 +12,22 @@ define(function (require, exports, modul
   const { div, span, table, tbody, tr, td, code } = dom;
 
   /**
    * This template is responsible for rendering basic layout
    * of the 'Headers' panel. It displays HTTP headers groups such as
    * received or response headers.
    */
   let Headers = createClass({
+    displayName: "Headers",
+
     propTypes: {
       data: PropTypes.object,
     },
 
-    displayName: "Headers",
-
     getInitialState: function () {
       return {};
     },
 
     render: function () {
       let data = this.props.data;
 
       return (
@@ -53,25 +53,25 @@ define(function (require, exports, modul
     }
   });
 
   /**
    * This template renders headers list,
    * name + value pairs.
    */
   let HeaderList = createFactory(createClass({
+    displayName: "HeaderList",
+
     propTypes: {
       headers: PropTypes.arrayOf(PropTypes.shape({
         name: PropTypes.string,
         value: PropTypes.string
       }))
     },
 
-    displayName: "HeaderList",
-
     getInitialState: function () {
       return {
         headers: []
       };
     },
 
     render: function () {
       let headers = this.props.headers;
--- a/devtools/client/jsonview/components/json-panel.js
+++ b/devtools/client/jsonview/components/json-panel.js
@@ -19,29 +19,29 @@ define(function (require, exports, modul
   const AUTO_EXPAND_MAX_LEVEL = 7;
 
   /**
    * This template represents the 'JSON' panel. The panel is
    * responsible for rendering an expandable tree that allows simple
    * inspection of JSON structure.
    */
   let JsonPanel = createClass({
+    displayName: "JsonPanel",
+
     propTypes: {
       data: PropTypes.oneOfType([
         PropTypes.string,
         PropTypes.array,
         PropTypes.object
       ]),
       jsonTextLength: PropTypes.number,
       searchFilter: PropTypes.string,
       actions: PropTypes.object,
     },
 
-    displayName: "JsonPanel",
-
     getInitialState: function () {
       return {};
     },
 
     componentDidMount: function () {
       document.addEventListener("keypress", this.onKeyPress, true);
     },
 
@@ -149,22 +149,22 @@ define(function (require, exports, modul
       );
     }
   });
 
   /**
    * This template represents a toolbar within the 'JSON' panel.
    */
   let JsonToolbar = createFactory(createClass({
+    displayName: "JsonToolbar",
+
     propTypes: {
       actions: PropTypes.object,
     },
 
-    displayName: "JsonToolbar",
-
     // Commands
 
     onSave: function (event) {
       this.props.actions.onSaveJson();
     },
 
     onCopy: function (event) {
       this.props.actions.onCopyJson();
--- a/devtools/client/jsonview/components/main-tabbed-area.js
+++ b/devtools/client/jsonview/components/main-tabbed-area.js
@@ -14,31 +14,31 @@ define(function (require, exports, modul
   const { HeadersPanel } = createFactories(require("./headers-panel"));
   const { Tabs, TabPanel } = createFactories(require("./reps/tabs"));
 
   /**
    * This object represents the root application template
    * responsible for rendering the basic tab layout.
    */
   let MainTabbedArea = createClass({
+    displayName: "MainTabbedArea",
+
     propTypes: {
       jsonText: PropTypes.string,
       tabActive: PropTypes.number,
       actions: PropTypes.object,
       headers: PropTypes.object,
       searchFilter: PropTypes.string,
       json: PropTypes.oneOfType([
         PropTypes.string,
         PropTypes.object,
         PropTypes.array
       ])
     },
 
-    displayName: "MainTabbedArea",
-
     getInitialState: function () {
       return {
         json: {},
         headers: {},
         jsonText: this.props.jsonText,
         tabActive: this.props.tabActive
       };
     },
--- a/devtools/client/jsonview/components/reps/tabs.js
+++ b/devtools/client/jsonview/components/reps/tabs.js
@@ -26,34 +26,34 @@ define(function (require, exports, modul
    *    </ul>
    *  </nav>
    *  <article class='tab-panel'>
    *    The content of active panel here
    *  </article>
    * <div>
    */
   let Tabs = React.createClass({
+    displayName: "Tabs",
+
     propTypes: {
       className: React.PropTypes.oneOfType([
         React.PropTypes.array,
         React.PropTypes.string,
         React.PropTypes.object
       ]),
       tabActive: React.PropTypes.number,
       onMount: React.PropTypes.func,
       onBeforeChange: React.PropTypes.func,
       onAfterChange: React.PropTypes.func,
       children: React.PropTypes.oneOfType([
         React.PropTypes.array,
         React.PropTypes.element
       ]).isRequired
     },
 
-    displayName: "Tabs",
-
     getDefaultProps: function () {
       return {
         tabActive: 1
       };
     },
 
     getInitialState: function () {
       return {
@@ -163,26 +163,26 @@ define(function (require, exports, modul
       );
     },
   });
 
   /**
    * Renders simple tab 'panel'.
    */
   let Panel = React.createClass({
+    displayName: "Panel",
+
     propTypes: {
       title: React.PropTypes.string.isRequired,
       children: React.PropTypes.oneOfType([
         React.PropTypes.array,
         React.PropTypes.element
       ]).isRequired
     },
 
-    displayName: "Panel",
-
     render: function () {
       return DOM.div({},
         this.props.children
       );
     }
   });
 
   // Exports from this module
--- a/devtools/client/jsonview/components/reps/toolbar.js
+++ b/devtools/client/jsonview/components/reps/toolbar.js
@@ -9,46 +9,46 @@
 define(function (require, exports, module) {
   const React = require("devtools/client/shared/vendor/react");
   const DOM = React.DOM;
 
   /**
    * Renders a simple toolbar.
    */
   let Toolbar = React.createClass({
+    displayName: "Toolbar",
+
     propTypes: {
       children: React.PropTypes.oneOfType([
         React.PropTypes.array,
         React.PropTypes.element
       ])
     },
 
-    displayName: "Toolbar",
-
     render: function () {
       return (
         DOM.div({className: "toolbar"},
           this.props.children
         )
       );
     }
   });
 
   /**
    * Renders a simple toolbar button.
    */
   let ToolbarButton = React.createClass({
+    displayName: "ToolbarButton",
+
     propTypes: {
       active: React.PropTypes.bool,
       disabled: React.PropTypes.bool,
       children: React.PropTypes.string,
     },
 
-    displayName: "ToolbarButton",
-
     render: function () {
       let props = Object.assign({className: "btn"}, this.props);
       return (
         DOM.button(props, this.props.children)
       );
     },
   });
 
--- a/devtools/client/jsonview/components/search-box.js
+++ b/devtools/client/jsonview/components/search-box.js
@@ -14,22 +14,22 @@ define(function (require, exports, modul
   // For smooth incremental searching (in case the user is typing quickly).
   const searchDelay = 250;
 
   /**
    * This object represents a search box located at the
    * top right corner of the application.
    */
   let SearchBox = createClass({
+    displayName: "SearchBox",
+
     propTypes: {
       actions: PropTypes.object,
     },
 
-    displayName: "SearchBox",
-
     onSearch: function (event) {
       let searchBox = event.target;
       let win = searchBox.ownerDocument.defaultView;
 
       if (this.searchTimeout) {
         win.clearTimeout(this.searchTimeout);
       }
 
--- a/devtools/client/jsonview/components/text-panel.js
+++ b/devtools/client/jsonview/components/text-panel.js
@@ -12,23 +12,23 @@ define(function (require, exports, modul
   const { Toolbar, ToolbarButton } = createFactories(require("./reps/toolbar"));
   const { div, pre } = dom;
 
   /**
    * This template represents the 'Raw Data' panel displaying
    * JSON as a text received from the server.
    */
   let TextPanel = createClass({
+    displayName: "TextPanel",
+
     propTypes: {
       actions: PropTypes.object,
       data: PropTypes.string
     },
 
-    displayName: "TextPanel",
-
     getInitialState: function () {
       return {};
     },
 
     render: function () {
       return (
         div({className: "textPanelBox"},
           TextToolbar({actions: this.props.actions}),
@@ -42,22 +42,22 @@ define(function (require, exports, modul
     }
   });
 
   /**
    * This object represents a toolbar displayed within the
    * 'Raw Data' panel.
    */
   let TextToolbar = createFactory(createClass({
+    displayName: "TextToolbar",
+
     propTypes: {
       actions: PropTypes.object,
     },
 
-    displayName: "TextToolbar",
-
     // Commands
 
     onPrettify: function (event) {
       this.props.actions.onPrettify();
     },
 
     onSave: function (event) {
       this.props.actions.onSaveJson();
--- a/devtools/client/responsive.html/app.js
+++ b/devtools/client/responsive.html/app.js
@@ -23,26 +23,26 @@ const { takeScreenshot } = require("./ac
 const { updateTouchSimulationEnabled } = require("./actions/touch-simulation");
 const DeviceModal = createFactory(require("./components/device-modal"));
 const GlobalToolbar = createFactory(require("./components/global-toolbar"));
 const Viewports = createFactory(require("./components/viewports"));
 const { updateDeviceList } = require("./devices");
 const Types = require("./types");
 
 let App = createClass({
+  displayName: "App",
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     location: Types.location.isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
     viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
   },
 
-  displayName: "App",
-
   onBrowserMounted() {
     window.postMessage({ type: "browser-mounted" }, "*");
   },
 
   onChangeViewportDevice(id, device) {
     this.props.dispatch(changeDevice(id, device));
   },
 
--- a/devtools/client/responsive.html/components/browser.js
+++ b/devtools/client/responsive.html/components/browser.js
@@ -17,24 +17,24 @@ const e10s = require("../utils/e10s");
 
 module.exports = createClass({
   /**
    * This component is not allowed to depend directly on frequently changing
    * data (width, height) due to the use of `dangerouslySetInnerHTML` below.
    * Any changes in props will cause the <iframe> to be removed and added again,
    * throwing away the current state of the page.
    */
+  displayName: "Browser",
+
   propTypes: {
     location: Types.location.isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
   },
 
-  displayName: "Browser",
-
   mixins: [ addons.PureRenderMixin ],
 
   /**
    * Once the browser element has mounted, load the frame script and enable
    * various features, like floating scrollbars.
    */
   componentDidMount: Task.async(function* () {
     let { onContentResize } = this;
--- a/devtools/client/responsive.html/components/device-modal.js
+++ b/devtools/client/responsive.html/components/device-modal.js
@@ -5,25 +5,25 @@
 "use strict";
 
 const { DOM: dom, createClass, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 const { getStr } = require("../utils/l10n");
 const Types = require("../types");
 
 module.exports = createClass({
+  displayName: "DeviceModal",
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     onDeviceListUpdate: PropTypes.func.isRequired,
     onUpdateDeviceDisplayed: PropTypes.func.isRequired,
     onUpdateDeviceModalOpen: PropTypes.func.isRequired,
   },
 
-  displayName: "DeviceModal",
-
   mixins: [ addons.PureRenderMixin ],
 
   getInitialState() {
     return {};
   },
 
   componentWillReceiveProps(nextProps) {
     let {
--- a/devtools/client/responsive.html/components/device-selector.js
+++ b/devtools/client/responsive.html/components/device-selector.js
@@ -7,26 +7,26 @@
 const { getStr } = require("../utils/l10n");
 const { DOM: dom, createClass, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
 
 module.exports = createClass({
+  displayName: "DeviceSelector",
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     selectedDevice: PropTypes.string.isRequired,
     onChangeViewportDevice: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
     onUpdateDeviceModalOpen: PropTypes.func.isRequired,
   },
 
-  displayName: "DeviceSelector",
-
   mixins: [ addons.PureRenderMixin ],
 
   onSelectChange({ target }) {
     let {
       devices,
       onChangeViewportDevice,
       onResizeViewport,
       onUpdateDeviceModalOpen,
--- a/devtools/client/responsive.html/components/global-toolbar.js
+++ b/devtools/client/responsive.html/components/global-toolbar.js
@@ -5,26 +5,26 @@
 "use strict";
 
 const { getStr } = require("../utils/l10n");
 const { DOM: dom, createClass, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 const Types = require("../types");
 
 module.exports = createClass({
+  displayName: "GlobalToolbar",
+
   propTypes: {
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
     onExit: PropTypes.func.isRequired,
     onScreenshot: PropTypes.func.isRequired,
     onUpdateTouchSimulationEnabled: PropTypes.func.isRequired,
   },
 
-  displayName: "GlobalToolbar",
-
   mixins: [ addons.PureRenderMixin ],
 
   render() {
     let {
       screenshot,
       touchSimulation,
       onExit,
       onScreenshot,
--- a/devtools/client/responsive.html/components/resizable-viewport.js
+++ b/devtools/client/responsive.html/components/resizable-viewport.js
@@ -13,31 +13,31 @@ const Constants = require("../constants"
 const Types = require("../types");
 const Browser = createFactory(require("./browser"));
 const ViewportToolbar = createFactory(require("./viewport-toolbar"));
 
 const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION;
 const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION;
 
 module.exports = createClass({
+  displayName: "ResizableViewport",
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     location: Types.location.isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     viewport: PropTypes.shape(Types.viewport).isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onChangeViewportDevice: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
     onRotateViewport: PropTypes.func.isRequired,
     onUpdateDeviceModalOpen: PropTypes.func.isRequired,
   },
 
-  displayName: "ResizableViewport",
-
   getInitialState() {
     return {
       isResizing: false,
       lastClientX: 0,
       lastClientY: 0,
       ignoreX: false,
       ignoreY: false,
     };
--- a/devtools/client/responsive.html/components/viewport-dimension.js
+++ b/devtools/client/responsive.html/components/viewport-dimension.js
@@ -6,24 +6,24 @@
 
 const { DOM: dom, createClass, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Constants = require("../constants");
 const Types = require("../types");
 
 module.exports = createClass({
+  displayName: "ViewportDimension",
+
   propTypes: {
     viewport: PropTypes.shape(Types.viewport).isRequired,
     onChangeViewportDevice: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
   },
 
-  displayName: "ViewportDimension",
-
   getInitialState() {
     let { width, height } = this.props.viewport;
 
     return {
       width,
       height,
       isEditing: false,
       isInvalid: false,
--- a/devtools/client/responsive.html/components/viewport-toolbar.js
+++ b/devtools/client/responsive.html/components/viewport-toolbar.js
@@ -6,27 +6,27 @@
 
 const { DOM: dom, createClass, createFactory, PropTypes, addons } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const DeviceSelector = createFactory(require("./device-selector"));
 
 module.exports = createClass({
+  displayName: "ViewportToolbar",
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     selectedDevice: PropTypes.string.isRequired,
     onChangeViewportDevice: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
     onRotateViewport: PropTypes.func.isRequired,
     onUpdateDeviceModalOpen: PropTypes.func.isRequired,
   },
 
-  displayName: "ViewportToolbar",
-
   mixins: [ addons.PureRenderMixin ],
 
   render() {
     let {
       devices,
       selectedDevice,
       onChangeViewportDevice,
       onResizeViewport,
--- a/devtools/client/responsive.html/components/viewport.js
+++ b/devtools/client/responsive.html/components/viewport.js
@@ -7,31 +7,31 @@
 const { DOM: dom, createClass, createFactory, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const ResizableViewport = createFactory(require("./resizable-viewport"));
 const ViewportDimension = createFactory(require("./viewport-dimension"));
 
 module.exports = createClass({
+  displayName: "Viewport",
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     location: Types.location.isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     viewport: PropTypes.shape(Types.viewport).isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onChangeViewportDevice: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
     onRotateViewport: PropTypes.func.isRequired,
     onUpdateDeviceModalOpen: PropTypes.func.isRequired,
   },
 
-  displayName: "Viewport",
-
   onChangeViewportDevice(device) {
     let {
       viewport,
       onChangeViewportDevice,
     } = this.props;
 
     onChangeViewportDevice(viewport.id, device);
   },
--- a/devtools/client/responsive.html/components/viewports.js
+++ b/devtools/client/responsive.html/components/viewports.js
@@ -6,31 +6,31 @@
 
 const { DOM: dom, createClass, createFactory, PropTypes } =
   require("devtools/client/shared/vendor/react");
 
 const Types = require("../types");
 const Viewport = createFactory(require("./viewport"));
 
 module.exports = createClass({
+  displayName: "Viewports",
+
   propTypes: {
     devices: PropTypes.shape(Types.devices).isRequired,
     location: Types.location.isRequired,
     screenshot: PropTypes.shape(Types.screenshot).isRequired,
     viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
     onBrowserMounted: PropTypes.func.isRequired,
     onChangeViewportDevice: PropTypes.func.isRequired,
     onContentResize: PropTypes.func.isRequired,
     onResizeViewport: PropTypes.func.isRequired,
     onRotateViewport: PropTypes.func.isRequired,
     onUpdateDeviceModalOpen: PropTypes.func.isRequired,
   },
 
-  displayName: "Viewports",
-
   render() {
     let {
       devices,
       location,
       screenshot,
       viewports,
       onBrowserMounted,
       onChangeViewportDevice,