diff options
Diffstat (limited to 'devtools/client/netmonitor/src/selectors/requests.js')
-rw-r--r-- | devtools/client/netmonitor/src/selectors/requests.js | 198 |
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, +}; |