Bug 1404917 - mutable reducer draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 05 Oct 2017 17:13:36 +0200
changeset 675598 bd62a4afa17f381d7dbe4625d9698639e15d6b79
parent 675597 a37ae0bc0fb58fccf8b926f73373b89b5064e841
child 675599 2f29937c190c7f5e8937b7fe29ae2b02e96079af
push id83180
push userbmo:poirot.alex@gmail.com
push dateThu, 05 Oct 2017 15:54:09 +0000
bugs1404917
milestone58.0a1
Bug 1404917 - mutable reducer MozReview-Commit-ID: MGGAkcnrXR
devtools/client/netmonitor/src/actions/index.js
devtools/client/netmonitor/src/actions/moz.build
devtools/client/netmonitor/src/actions/requests-data.js
devtools/client/netmonitor/src/actions/requests.js
devtools/client/netmonitor/src/components/response-panel.js
devtools/client/netmonitor/src/connector/firefox-data-provider.js
devtools/client/netmonitor/src/constants.js
devtools/client/netmonitor/src/reducers/index.js
devtools/client/netmonitor/src/reducers/moz.build
devtools/client/netmonitor/src/reducers/requests-data.js
devtools/client/netmonitor/src/utils/create-store.js
--- a/devtools/client/netmonitor/src/actions/index.js
+++ b/devtools/client/netmonitor/src/actions/index.js
@@ -2,22 +2,24 @@
  * 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 batching = require("./batching");
 const filters = require("./filters");
 const requests = require("./requests");
+const requestsData = require("./requests-data");
 const selection = require("./selection");
 const sort = require("./sort");
 const timingMarkers = require("./timing-markers");
 const ui = require("./ui");
 
 Object.assign(exports,
   batching,
   filters,
   requests,
+  requestsData,
   selection,
   sort,
   timingMarkers,
   ui
 );
--- a/devtools/client/netmonitor/src/actions/moz.build
+++ b/devtools/client/netmonitor/src/actions/moz.build
@@ -1,14 +1,15 @@
 # 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/.
 
 DevToolsModules(
     'batching.js',
     'filters.js',
     'index.js',
+    'requests-data.js',
     'requests.js',
     'selection.js',
     'sort.js',
     'timing-markers.js',
     'ui.js',
 )
copy from devtools/client/netmonitor/src/actions/index.js
copy to devtools/client/netmonitor/src/actions/requests-data.js
--- a/devtools/client/netmonitor/src/actions/index.js
+++ b/devtools/client/netmonitor/src/actions/requests-data.js
@@ -1,23 +1,23 @@
 /* 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 batching = require("./batching");
-const filters = require("./filters");
-const requests = require("./requests");
-const selection = require("./selection");
-const sort = require("./sort");
-const timingMarkers = require("./timing-markers");
-const ui = require("./ui");
+const {
+  ADD_REQUEST_DATA,
+} = require("../constants");
+
+function addRequestData(id, data, batch) {
+  return {
 
-Object.assign(exports,
-  batching,
-  filters,
-  requests,
-  selection,
-  sort,
-  timingMarkers,
-  ui
-);
+    type: ADD_REQUEST_DATA,
+    id,
+    data,
+    meta: { batch },
+  };
+}
+
+module.exports = {
+  addRequestData,
+};
--- a/devtools/client/netmonitor/src/actions/requests.js
+++ b/devtools/client/netmonitor/src/actions/requests.js
@@ -2,16 +2,17 @@
  * 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 { sendHTTPRequest } = require("../connector/index");
 const {
   ADD_REQUEST,
+  ADD_REQUEST_DATA,
   CLEAR_REQUESTS,
   CLONE_SELECTED_REQUEST,
   REMOVE_SELECTED_CUSTOM_REQUEST,
   SEND_CUSTOM_REQUEST,
   UPDATE_REQUEST,
 } = require("../constants");
 const { getSelectedRequest } = require("../selectors/index");
 
@@ -28,16 +29,26 @@ function updateRequest(id, data, batch) 
   return {
     type: UPDATE_REQUEST,
     id,
     data,
     meta: { batch },
   };
 }
 
+function addRequestData(id, data, batch) {
+  return {
+
+    type: ADD_REQUEST_DATA,
+    id,
+    data,
+    meta: { batch },
+  };
+}
+
 /**
  * Clone the currently selected request, set the "isCustom" attribute.
  * Used by the "Edit and Resend" feature.
  */
 function cloneSelectedRequest() {
   return {
     type: CLONE_SELECTED_REQUEST
   };
@@ -89,14 +100,15 @@ function removeSelectedCustomRequest() {
 function clearRequests() {
   return {
     type: CLEAR_REQUESTS
   };
 }
 
 module.exports = {
   addRequest,
+  addRequestData,
   clearRequests,
   cloneSelectedRequest,
   removeSelectedCustomRequest,
   sendCustomRequest,
   updateRequest,
 };
--- a/devtools/client/netmonitor/src/components/response-panel.js
+++ b/devtools/client/netmonitor/src/components/response-panel.js
@@ -5,32 +5,34 @@
 "use strict";
 
 const {
   createClass,
   createFactory,
   DOM,
   PropTypes,
 } = require("devtools/client/shared/vendor/react");
+const { connect } = require("devtools/client/shared/vendor/react-redux");
 const { L10N } = require("../utils/l10n");
 const { formDataURI, getUrlBaseName } = require("../utils/request-utils");
 
 const { getResponseContent } = require("../connector/index");
 
 // Components
 const PropertiesView = createFactory(require("./properties-view"));
 
 const { div, img } = DOM;
 const JSON_SCOPE_NAME = L10N.getStr("jsonScopeName");
 const JSON_FILTER_TEXT = L10N.getStr("jsonFilterText");
 const RESPONSE_IMG_NAME = L10N.getStr("netmonitor.response.name");
 const RESPONSE_IMG_DIMENSIONS = L10N.getStr("netmonitor.response.dimensions");
 const RESPONSE_IMG_MIMETYPE = L10N.getStr("netmonitor.response.mime");
 const RESPONSE_PAYLOAD = L10N.getStr("responsePayload");
 
+
 /*
  * Response panel component
  * Displays the GET parameters and POST data of a request
  */
 const ResponsePanel = createClass({
   displayName: "ResponsePanel",
 
   propTypes: {
@@ -113,28 +115,28 @@ const ResponsePanel = createClass({
   },
 
   // componentWillReceiveProps is the only method called when switching to the
   // ResponsePanel *and* when being on it and switching between two requests.
   componentWillReceiveProps(nextProps) {
     // When switching to another request lazily fetch response content
     // from the backend. The Response Panel will first be empty and then
     // display the content.
-    if (!nextProps.request.responseContent ||
-        !nextProps.request.responseContent.content) {
-      // This method will set `props.request.responseContent.content`
-      // asynchronously and introduce another render.
+    if (!nextProps.requestsData.responses.has(request.id)) {
+      // This method will add an entry in `props.requestsData.responses` for the
+      // current request asynchronously and introduce another render.
       getResponseContent(nextProps.request.id);
     }
   },
 
   render() {
     let { openLink, request } = this.props;
-    let { responseContent, url } = request;
+    let { url } = request;
 
+    let responseContent = this.props.requestsData.responses.get(request.id);
     if (!responseContent || typeof responseContent.content.text !== "string") {
       return null;
     }
 
     let { encoding, mimeType, text } = responseContent.content;
 
     if (mimeType.includes("image/")) {
       let { width, height } = this.state.imageDimensions;
@@ -195,9 +197,13 @@ const ResponsePanel = createClass({
           sectionNames: Object.keys(object),
           openLink,
         }),
       )
     );
   }
 });
 
-module.exports = ResponsePanel;
+module.exports = connect(
+  (state, props) => ({
+    requestsData: state.requestsData,
+  })
+)(ResponsePanel);
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js
+++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js
@@ -131,20 +131,17 @@ class FirefoxDataProvider {
       responseCookiesObj
     );
 
     this.pushPayloadToQueue(id, payload);
 
     if (this.actions.updateRequest && this.isQueuePayloadReady(id)) {
       let payload = this.getPayloadFromQueue(id).payload;
       await this.actions.updateRequest(id, payload, true);
-      return payload;
     }
-
-    return payload;
   }
 
   async fetchImage(mimeType, responseContent) {
     let payload = {};
     if (mimeType && responseContent && responseContent.content) {
       let { encoding, text } = responseContent.content;
       let response = await this.getLongString(text);
 
@@ -323,25 +320,36 @@ class FirefoxDataProvider {
     }
     // Prevent fetching the response more than once at a time
     // in case this method is called multiple times in a raw.
     if (this.pendingResponseContentRequests.has(id)) {
       return this.pendingResponseContentRequests.get(id);
     }
     let promise = this.webConsoleClient.getResponseContent(id)
       .then(async response => {
-        // We have to pass mimeType in order to ensure calling fetchImage in updateRequest
-        // and have the LongString in `response.content.text` converted to text.
-        let payload = await this.updateRequest(id, {
-          responseContent: response,
-          mimeType: response.content.mimeType
-        });
+        let { mimeType } = response.content;
+        let { encoding, text } = response.content;
+        let textString = await this.getLongString(text);
+
+        let data = {
+          content: {
+            encoding,
+            mimeType,
+            text: textString,
+          },
+        };
+        if (mimeType.includes("image/")) {
+          data.responseContentDataUri = formDataURI(mimeType, encoding, response);
+        }
+        await this.actions.addRequestData(id, data, true);
+
         this.pendingResponseContentRequests.delete(id);
         emit(EVENTS.RECEIVED_RESPONSE_CONTENT, id);
-        return payload.responseContent;
+
+        return data;
       });
     this.pendingResponseContentRequests.set(id, promise);
     emit(EVENTS.UPDATING_RESPONSE_CONTENT, id);
     return promise;
   }
 
   /**
    * The "networkEvent" message type handler.
--- a/devtools/client/netmonitor/src/constants.js
+++ b/devtools/client/netmonitor/src/constants.js
@@ -1,16 +1,17 @@
 /* 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 actionTypes = {
   ADD_REQUEST: "ADD_REQUEST",
+  ADD_REQUEST_DATA: "ADD_REQUEST_DATA",
   ADD_TIMING_MARKER: "ADD_TIMING_MARKER",
   BATCH_ACTIONS: "BATCH_ACTIONS",
   BATCH_ENABLE: "BATCH_ENABLE",
   CLEAR_REQUESTS: "CLEAR_REQUESTS",
   CLEAR_TIMING_MARKERS: "CLEAR_TIMING_MARKERS",
   CLONE_SELECTED_REQUEST: "CLONE_SELECTED_REQUEST",
   ENABLE_REQUEST_FILTER_TYPE_ONLY: "ENABLE_REQUEST_FILTER_TYPE_ONLY",
   OPEN_NETWORK_DETAILS: "OPEN_NETWORK_DETAILS",
--- a/devtools/client/netmonitor/src/reducers/index.js
+++ b/devtools/client/netmonitor/src/reducers/index.js
@@ -2,22 +2,24 @@
  * 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 { combineReducers } = require("devtools/client/shared/vendor/redux");
 const batchingReducer = require("./batching");
 const { requestsReducer } = require("./requests");
+const { requestsDataReducer } = require("./requests-data");
 const { sortReducer } = require("./sort");
 const { filters } = require("./filters");
 const { timingMarkers } = require("./timing-markers");
 const { ui } = require("./ui");
 
 module.exports = batchingReducer(
   combineReducers({
     requests: requestsReducer,
+    requestsData: requestsDataReducer,
     sort: sortReducer,
     filters,
     timingMarkers,
     ui,
   })
 );
--- a/devtools/client/netmonitor/src/reducers/moz.build
+++ b/devtools/client/netmonitor/src/reducers/moz.build
@@ -1,13 +1,14 @@
 # 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/.
 
 DevToolsModules(
     'batching.js',
     'filters.js',
     'index.js',
+    'requests-data.js',
     'requests.js',
     'sort.js',
     'timing-markers.js',
     'ui.js',
 )
copy from devtools/client/netmonitor/src/actions/index.js
copy to devtools/client/netmonitor/src/reducers/requests-data.js
--- a/devtools/client/netmonitor/src/actions/index.js
+++ b/devtools/client/netmonitor/src/reducers/requests-data.js
@@ -1,23 +1,29 @@
 /* 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 batching = require("./batching");
-const filters = require("./filters");
-const requests = require("./requests");
-const selection = require("./selection");
-const sort = require("./sort");
-const timingMarkers = require("./timing-markers");
-const ui = require("./ui");
+const {
+  ADD_REQUEST_DATA,
+} = require("../constants");
+
+var initialState = {
+  responses: new Map(),
+};
 
-Object.assign(exports,
-  batching,
-  filters,
-  requests,
-  selection,
-  sort,
-  timingMarkers,
-  ui
-);
+function requestsDataReducer(state = initialState, action) {
+  switch (action.type) {
+    case ADD_REQUEST_DATA: {
+      return {
+        responses: state.responses.set(action.id, action.data),
+      };
+    }
+    default:
+      return state;
+  }
+}
+
+module.exports = {
+  requestsDataReducer,
+};
--- a/devtools/client/netmonitor/src/utils/create-store.js
+++ b/devtools/client/netmonitor/src/utils/create-store.js
@@ -40,16 +40,19 @@ function configureStore() {
     });
   }
 
   const initialState = {
     filters: new Filters({
       requestFilterTypes: new FilterTypes(activeFilters)
     }),
     requests: new Requests(),
+    requestsData: {
+      responses: new Map(),
+    },
     sort: new Sort(),
     timingMarkers: new TimingMarkers(),
     ui: new UI({
       columns,
     }),
   };
 
   return createStore(rootReducer, initialState, applyMiddleware(thunk, prefs, batching));