summaryrefslogtreecommitdiffstats
path: root/devtools/client/netmonitor/src/selectors/requests.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/netmonitor/src/selectors/requests.js')
-rw-r--r--devtools/client/netmonitor/src/selectors/requests.js198
1 files changed, 198 insertions, 0 deletions
diff --git a/devtools/client/netmonitor/src/selectors/requests.js b/devtools/client/netmonitor/src/selectors/requests.js
new file mode 100644
index 0000000000..afe9b7ecaf
--- /dev/null
+++ b/devtools/client/netmonitor/src/selectors/requests.js
@@ -0,0 +1,198 @@
+/* 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 {
+ createSelector,
+} = require("resource://devtools/client/shared/vendor/reselect.js");
+const {
+ Filters,
+ isFreetextMatch,
+} = require("resource://devtools/client/netmonitor/src/utils/filter-predicates.js");
+const {
+ Sorters,
+} = require("resource://devtools/client/netmonitor/src/utils/sort-predicates.js");
+
+/**
+ * Take clones into account when sorting.
+ * If a request is a clone, use the original request for comparison.
+ * If one of the compared request is a clone of the other, sort them next to each other.
+ */
+function sortWithClones(requests, sorter, a, b) {
+ const aId = a.id,
+ bId = b.id;
+
+ if (aId.endsWith("-clone")) {
+ const aOrigId = aId.replace(/-clone$/, "");
+ if (aOrigId === bId) {
+ return +1;
+ }
+ a = requests.find(item => item.id === aOrigId);
+ }
+
+ if (bId.endsWith("-clone")) {
+ const bOrigId = bId.replace(/-clone$/, "");
+ if (bOrigId === aId) {
+ return -1;
+ }
+ b = requests.find(item => item.id === bOrigId);
+ }
+
+ const defaultSorter = () => false;
+ return sorter ? sorter(a, b) : defaultSorter;
+}
+
+/**
+ * Take clones into account when filtering. If a request is
+ * a clone, it's not filtered out.
+ */
+const getFilterWithCloneFn = createSelector(
+ state => state.filters,
+ filters => r => {
+ const matchesType = Object.keys(filters.requestFilterTypes).some(filter => {
+ if (r.id.endsWith("-clone")) {
+ return true;
+ }
+ return (
+ filters.requestFilterTypes[filter] &&
+ Filters[filter] &&
+ Filters[filter](r)
+ );
+ });
+ return matchesType && isFreetextMatch(r, filters.requestFilterText);
+ }
+);
+
+const getTypeFilterFn = createSelector(
+ state => state.filters,
+ filters => r => {
+ return Object.keys(filters.requestFilterTypes).some(filter => {
+ return (
+ filters.requestFilterTypes[filter] &&
+ Filters[filter] &&
+ Filters[filter](r)
+ );
+ });
+ }
+);
+
+const getSortFn = createSelector(
+ state => state.requests,
+ state => state.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,
+ getSortFn,
+ ({ requests }, sortFn) => [...requests].sort(sortFn)
+);
+
+const getDisplayedRequests = createSelector(
+ state => state.requests,
+ getFilterWithCloneFn,
+ getSortFn,
+ ({ requests }, filterFn, sortFn) => requests.filter(filterFn).sort(sortFn)
+);
+
+const getTypeFilteredRequests = createSelector(
+ state => state.requests,
+ getTypeFilterFn,
+ ({ requests }, filterFn) => requests.filter(filterFn)
+);
+
+const getDisplayedRequestsSummary = createSelector(
+ getDisplayedRequests,
+ state => state.requests.lastEndedMs - state.requests.firstStartedMs,
+ (requests, totalMs) => {
+ if (requests.length === 0) {
+ return { count: 0, bytes: 0, ms: 0 };
+ }
+
+ const totalBytes = requests.reduce(
+ (totals, item) => {
+ if (typeof item.contentSize == "number") {
+ totals.contentSize += item.contentSize;
+ }
+
+ if (
+ typeof item.transferredSize == "number" &&
+ !(item.fromCache || item.status === "304")
+ ) {
+ totals.transferredSize += item.transferredSize;
+ }
+
+ return totals;
+ },
+ { contentSize: 0, transferredSize: 0 }
+ );
+
+ return {
+ count: requests.length,
+ contentSize: totalBytes.contentSize,
+ ms: totalMs,
+ transferredSize: totalBytes.transferredSize,
+ };
+ }
+);
+
+const getSelectedRequest = createSelector(
+ state => state.requests,
+ ({ selectedId, requests }) =>
+ selectedId ? requests.find(item => item.id === selectedId) : undefined
+);
+
+const isSelectedRequestVisible = createSelector(
+ state => state.requests,
+ getDisplayedRequests,
+ ({ selectedId }, displayedRequests) =>
+ displayedRequests.some(r => r.id === selectedId)
+);
+
+function getRequestById(state, id) {
+ return state.requests.requests.find(item => item.id === id);
+}
+
+function getRequestByChannelId(state, channelId) {
+ return [...state.requests.requests.values()].find(
+ r => r.resourceId == channelId
+ );
+}
+
+function getDisplayedRequestById(state, id) {
+ return getDisplayedRequests(state).find(r => r.id === id);
+}
+
+/**
+ * Returns the current recording boolean state (HTTP traffic is
+ * monitored or not monitored)
+ */
+function getRecordingState(state) {
+ return state.requests.recording;
+}
+
+const getClickedRequest = createSelector(
+ state => state.requests,
+ ({ requests, clickedRequestId }) =>
+ requests.find(request => request.id == clickedRequestId)
+);
+
+module.exports = {
+ getClickedRequest,
+ getDisplayedRequestById,
+ getDisplayedRequests,
+ getDisplayedRequestsSummary,
+ getRecordingState,
+ getRequestById,
+ getRequestByChannelId,
+ getSelectedRequest,
+ getSortedRequests,
+ getTypeFilteredRequests,
+ isSelectedRequestVisible,
+};