Bug 1408182 - remove immutable from requests store draft
authorAlexandre Poirot <poirot.alex@gmail.com>
Wed, 11 Oct 2017 17:35:09 +0200
changeset 695507 5bde21b4097afe83c836915df5252b1d73e2ee61
parent 695505 0f65679874c9b051036263ea491a162e6c30d062
child 739616 3654ef0cecf97c29b495baf0ebc933b6e6f73bf4
push id88442
push userbmo:poirot.alex@gmail.com
push dateThu, 09 Nov 2017 09:21:22 +0000
bugs1408182
milestone58.0a1
Bug 1408182 - remove immutable from requests store MozReview-Commit-ID: 4ZiOVYqkeU
devtools/client/netmonitor/src/reducers/requests.js
devtools/client/netmonitor/src/selectors/requests.js
devtools/client/netmonitor/src/selectors/ui.js
--- a/devtools/client/netmonitor/src/reducers/requests.js
+++ b/devtools/client/netmonitor/src/reducers/requests.js
@@ -1,31 +1,31 @@
 /* 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 I = require("devtools/client/shared/vendor/immutable");
+//const I = require("devtools/client/shared/vendor/immutable");
 const {
   getUrlDetails,
   processNetworkUpdates,
 } = require("../utils/request-utils");
 const {
   ADD_REQUEST,
   CLEAR_REQUESTS,
   CLONE_SELECTED_REQUEST,
   OPEN_NETWORK_DETAILS,
   REMOVE_SELECTED_CUSTOM_REQUEST,
   SELECT_REQUEST,
   SEND_CUSTOM_REQUEST,
   TOGGLE_RECORDING,
   UPDATE_REQUEST,
 } = require("../constants");
-
+/*
 const Request = I.Record({
   id: null,
   // Set to true in case of a request that's being edited as part of "edit and resend"
   isCustom: false,
   // Request properties - at the beginning, they are unknown and are gradually filled in
   startedMillis: undefined,
   endedMillis: undefined,
   method: undefined,
@@ -56,29 +56,53 @@ const Request = I.Record({
   requestCookies: undefined,
   requestPostData: undefined,
   responseHeaders: undefined,
   responseCookies: undefined,
   responseContent: undefined,
   responseContentAvailable: false,
   formDataSections: undefined,
 });
+*/
 
-const Requests = I.Record({
-  // The collection of requests (keyed by id)
-  requests: I.Map(),
-  // Selection state
-  selectedId: null,
-  preselectedId: null,
-  // Auxiliary fields to hold requests stats
-  firstStartedMillis: +Infinity,
-  lastEndedMillis: -Infinity,
-  // Recording state
-  recording: true,
-});
+function Requests(wasRecording=true) {
+  let state = {
+    requests: new Map(),
+    // Selection state
+    selectedId: null,
+    preselectedId: null,
+
+    recording: true,
+
+    // Auxiliary fields to hold requests stats
+    firstStartedMillis: +Infinity,
+    lastEndedMillis: -Infinity,
+
+
+    valueSeq() {
+      return [...state.requests.values()];
+    },
+    isEmpty() {
+      return state.requests.size == 0;
+    },
+    get(name) {
+      return state[name];
+    }
+  };
+  state.requests.isEmpty = () => {
+    return state.isEmpty();
+  };
+  state.requests.valueSeq = () => {
+    return state.valueSeq();
+  };
+  state.requests.filter = (...args) => {
+    return [...state.requests.values()].filter(...args);
+  };
+  return state;
+}
 
 /**
  * Remove the currently selected custom request.
  */
 function closeCustomRequest(state) {
   let { requests, selectedId } = state;
 
   if (!selectedId) {
@@ -93,74 +117,117 @@ function closeCustomRequest(state) {
   }
 
   return state.withMutations(st => {
     st.requests = st.requests.delete(selectedId);
     st.selectedId = null;
   });
 }
 
-function requestsReducer(state = new Requests(), action) {
+function requestsReducer(state = Requests() , action) {
   switch (action.type) {
     case ADD_REQUEST: {
-      return state.withMutations(st => {
-        let newRequest = new Request(Object.assign(
-          { id: action.id },
-          action.data,
-          { urlDetails: getUrlDetails(action.data.url) }
-        ));
-        st.requests = st.requests.set(newRequest.id, newRequest);
+      let st = Object.assign({}, state);
+
+      let newRequest = Object.assign(
+        { id: action.id },
+        action.data,
+        { urlDetails: getUrlDetails(action.data.url) }
+      );
+      st.requests.set(newRequest.id, newRequest);
+
+      // Update the started/ended timestamps
+      let { startedMillis } = action.data;
+      if (startedMillis < st.firstStartedMillis) {
+        st.firstStartedMillis = startedMillis;
+      }
+      if (startedMillis > st.lastEndedMillis) {
+        st.lastEndedMillis = startedMillis;
+      }
 
-        // Update the started/ended timestamps
-        let { startedMillis } = action.data;
-        if (startedMillis < st.firstStartedMillis) {
-          st.firstStartedMillis = startedMillis;
-        }
-        if (startedMillis > st.lastEndedMillis) {
-          st.lastEndedMillis = startedMillis;
+      // Select the request if it was preselected and there is no other selection
+      if (st.preselectedId && st.preselectedId === action.id) {
+        st.selectedId = st.selectedId || st.preselectedId;
+        st.preselectedId = null;
+      }
+      return st;
+    }
+    case UPDATE_REQUEST: {
+      let { requests, lastEndedMillis } = state;
+
+      let request = requests.get(action.id);
+      if (!request) {
+        return state;
+      }
+      request = Object.assign({}, request);
+      requests.set(action.id, request);
+
+      let st = Object.assign({}, state);
+      for (let [key, value] of Object.entries(action.data)) {
+        if (!UPDATE_PROPS.includes(key)) {
+          continue;
         }
 
-        // Select the request if it was preselected and there is no other selection
-        if (st.preselectedId && st.preselectedId === action.id) {
-          st.selectedId = st.selectedId || st.preselectedId;
-          st.preselectedId = null;
+        request[key] = value;
+
+        switch (key) {
+          case "url":
+            // Compute the additional URL details
+            request.urlDetails = getUrlDetails(value);
+            break;
+          case "totalTime":
+            request.endedMillis = request.startedMillis + value;
+            lastEndedMillis = Math.max(lastEndedMillis, request.endedMillis);
+            break;
+          case "requestPostData":
+            request.requestHeadersFromUploadStream = {
+              headers: [],
+              headersSize: 0,
+            };
+            break;
         }
-      });
+      }
+
+      st.lastEndedMillis = lastEndedMillis;
+      return st;
     }
     case CLEAR_REQUESTS: {
-      return new Requests({
-        recording: state.recording
-      });
+      return Requests(state.recording);
+    }
+    case SELECT_REQUEST: {
+      let st = Object.assign({}, state);
+      st.selectedId = action.id;
+      return st;
     }
     case CLONE_SELECTED_REQUEST: {
       let { requests, selectedId } = state;
 
       if (!selectedId) {
         return state;
       }
 
       let clonedRequest = requests.get(selectedId);
       if (!clonedRequest) {
         return state;
       }
+      let st = Object.assign({}, state);
 
-      let newRequest = new Request({
+      let newRequest = {
         id: clonedRequest.id + "-clone",
         method: clonedRequest.method,
         url: clonedRequest.url,
         urlDetails: clonedRequest.urlDetails,
         requestHeaders: clonedRequest.requestHeaders,
         requestPostData: clonedRequest.requestPostData,
         isCustom: true
-      });
+      };
 
-      return state.withMutations(st => {
-        st.requests = requests.set(newRequest.id, newRequest);
-        st.selectedId = newRequest.id;
-      });
+      requests.set(newRequest.id, newRequest);
+      st.selectedId = newRequest.id;
+      return st;
     }
     case OPEN_NETWORK_DETAILS: {
       if (!action.open) {
         return state.set("selectedId", null);
       }
 
       if (!state.selectedId && !state.requests.isEmpty()) {
         return state.set("selectedId", state.requests.first().id);
@@ -176,35 +243,33 @@ function requestsReducer(state = new Req
     }
     case SEND_CUSTOM_REQUEST: {
       // When a new request with a given id is added in future, select it immediately.
       // where we know in advance the ID of the request, at a time when it
       // wasn't sent yet.
       return closeCustomRequest(state.set("preselectedId", action.id));
     }
     case TOGGLE_RECORDING: {
-      return state.set("recording", !state.recording);
+      let st = Object.assign({}, state);
+      st.recording = !st.recording;
+      return st;
     }
-    case UPDATE_REQUEST: {
-      let { requests, lastEndedMillis } = state;
-
-      let updatedRequest = requests.get(action.id);
-      if (!updatedRequest) {
-        return state;
+    case OPEN_NETWORK_DETAILS: {
+      let st = Object.assign({}, state);
+      if (!action.open) {
+        state.selectedId = null;
+        return st;
       }
 
       updatedRequest = updatedRequest.withMutations(request => {
         let values = processNetworkUpdates(action.data);
         request = Object.assign(request, values);
       });
 
-      return state.withMutations(st => {
-        st.requests = requests.set(updatedRequest.id, updatedRequest);
-        st.lastEndedMillis = lastEndedMillis;
-      });
+      return st;
     }
 
     default:
       return state;
   }
 }
 
 module.exports = {
--- a/devtools/client/netmonitor/src/selectors/requests.js
+++ b/devtools/client/netmonitor/src/selectors/requests.js
@@ -51,43 +51,43 @@ const getTypeFilterFn = createSelector(
     const matchesType = filters.requestFilterTypes.some((enabled, filter) => {
       return enabled && Filters[filter] && Filters[filter](r);
     });
     return matchesType;
   }
 );
 
 const getSortFn = createSelector(
-  state => state.requests.requests,
+  state => state.requests,
   state => state.sort,
-  (requests, sort) => {
+  ({requests}, sort) => {
     const sorter = Sorters[sort.type || "waterfall"];
     const ascending = sort.ascending ? +1 : -1;
     return (a, b) => ascending * sortWithClones(requests, sorter, a, b);
   }
 );
 
 const getSortedRequests = createSelector(
-  state => state.requests.requests,
+  state => state.requests,
   getSortFn,
-  (requests, sortFn) => requests.valueSeq().sort(sortFn).toList()
+  ({requests}, sortFn) => requests.valueSeq().sort(sortFn)
 );
 
 const getDisplayedRequests = createSelector(
-  state => state.requests.requests,
+  state => state.requests,
   getFilterFn,
   getSortFn,
-  (requests, filterFn, sortFn) => requests.valueSeq()
-    .filter(filterFn).sort(sortFn).toList()
+  ({requests}, filterFn, sortFn) => requests.valueSeq()
+    .filter(filterFn).sort(sortFn)
 );
 
 const getTypeFilteredRequests = createSelector(
-  state => state.requests.requests,
+  state => state.requests,
   getTypeFilterFn,
-  (requests, filterFn) => requests.valueSeq().filter(filterFn).toList()
+  ({requests}, filterFn) => requests.valueSeq().filter(filterFn)
 );
 
 const getDisplayedRequestsSummary = createSelector(
   getDisplayedRequests,
   state => state.requests.lastEndedMillis - state.requests.firstStartedMillis,
   (requests, totalMillis) => {
     if (requests.size == 0) {
       return { count: 0, bytes: 0, millis: 0 };
--- a/devtools/client/netmonitor/src/selectors/ui.js
+++ b/devtools/client/netmonitor/src/selectors/ui.js
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { REQUESTS_WATERFALL } = require("../constants");
 const { getDisplayedRequests } = require("./requests");
 
 function isNetworkDetailsToggleButtonDisabled(state) {
-  return getDisplayedRequests(state).isEmpty();
+  return getDisplayedRequests(state).length == 0;
 }
 
 const EPSILON = 0.001;
 
 function getWaterfallScale(state) {
   const { requests, timingMarkers, ui } = state;
 
   if (requests.firstStartedMillis === +Infinity || ui.waterfallWidth === null) {