Source code
Revision control
Copy as Markdown
Other Tools
/* 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
"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.fromServiceWorker || 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,
};