fix(frontend): correct time adjustment for resources+merge with payloads by name + show body only if present

This commit is contained in:
Alex Kaminskii 2022-12-12 15:39:51 +01:00
parent b819e86945
commit 6054aef8e5
6 changed files with 29 additions and 25 deletions

View file

@ -153,10 +153,12 @@ function NetworkPanel() {
const activeTab = devTools[INDEX_KEY].activeTab; const activeTab = devTools[INDEX_KEY].activeTab;
const activeIndex = devTools[INDEX_KEY].index; const activeIndex = devTools[INDEX_KEY].index;
const list = useMemo(() => const list = useMemo(() =>
// TODO: better merge (with body size info)
resourceList.filter(res => !fetchList.some(ft => { resourceList.filter(res => !fetchList.some(ft => {
if (res.url !== ft.url) { return false } // res.url !== ft.url doesn't work on relative URLs appearing within fetchList (to-fix in player)
if (Math.abs(res.time - ft.time) > 200) { return false } // TODO: find good epsilons if (res.name !== ft.name) { return false }
if (Math.abs(res.time - ft.time) > 150) { return false } // TODO: find good epsilons
if (Math.abs(res.duration - ft.duration) > 100) { return false } if (Math.abs(res.duration - ft.duration) > 100) { return false }
return true return true
})) }))

View file

@ -22,15 +22,17 @@ function FetchTabs(props: Props) {
const onTabClick = (tab: string) => setActiveTab(tab); const onTabClick = (tab: string) => setActiveTab(tab);
const [jsonRequest, setJsonRequest] = useState<Object | string | null>(null); const [jsonRequest, setJsonRequest] = useState<Object | string | null>(null);
const [jsonResponse, setJsonResponse] = useState<Object | string | null>(null); const [jsonResponse, setJsonResponse] = useState<Object | string | null>(null);
const [requestHeaders, setRequestHeaders] = useState(null); const [requestHeaders, setRequestHeaders] = useState<Record<string,string> | null>(null);
const [responseHeaders, setResponseHeaders] = useState(null); const [responseHeaders, setResponseHeaders] = useState<Record<string,string> | null>(null);
useEffect(() => { useEffect(() => {
const { request, response } = resource; const { request, response } = resource;
try { try {
let jRequest = JSON.parse(request) let jRequest = JSON.parse(request)
setRequestHeaders(jRequest.headers); if (typeof jRequest.headers === "object") {
setRequestHeaders(jRequest.headers);
}
try { try {
let jBody = JSON.parse(jRequest.body) let jBody = JSON.parse(jRequest.body)
jBody = isValidJSON(jBody) ? jBody : jRequest.body jBody = isValidJSON(jBody) ? jBody : jRequest.body
@ -42,7 +44,9 @@ function FetchTabs(props: Props) {
try { try {
let jResponse = JSON.parse(response) let jResponse = JSON.parse(response)
setResponseHeaders(jResponse.headers); if (typeof jResponse.headers === "object") {
setResponseHeaders(jResponse.headers);
}
try { try {
let jBody = JSON.parse(jResponse.body) let jBody = JSON.parse(jResponse.body)
jBody = isValidJSON(jBody) ? jBody : jResponse.body jBody = isValidJSON(jBody) ? jBody : jResponse.body
@ -66,13 +70,13 @@ function FetchTabs(props: Props) {
</div> </div>
} }
size="small" size="small"
show={!request} show={!jsonRequest}
// animatedIcon="no-results" // animatedIcon="no-results"
> >
<div> <div>
<div className="mt-6"> <div className="mt-6">
{ !isValidJSON(jsonRequest) ? ( { !isValidJSON(jsonRequest) ? (
<div className="ml-3 break-words my-3"> {jsonRequest || request} </div> <div className="ml-3 break-words my-3"> {jsonRequest} </div>
) : ( ) : (
<JSONTree src={jsonRequest} collapsed={false} enableClipboard /> <JSONTree src={jsonRequest} collapsed={false} enableClipboard />
)} )}
@ -91,13 +95,13 @@ function FetchTabs(props: Props) {
</div> </div>
} }
size="small" size="small"
show={!response} show={!jsonResponse}
// animatedIcon="no-results" // animatedIcon="no-results"
> >
<div> <div>
<div className="mt-6"> <div className="mt-6">
{ !isValidJSON(jsonResponse) ? ( { !isValidJSON(jsonResponse) ? (
<div className="ml-3 break-words my-3"> {jsonResponse || response} </div> <div className="ml-3 break-words my-3"> {jsonResponse} </div>
) : ( ) : (
<JSONTree src={jsonResponse} collapsed={false} enableClipboard /> <JSONTree src={jsonResponse} collapsed={false} enableClipboard />
)} )}

View file

@ -4,8 +4,8 @@ import stl from './headers.module.css';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG'; import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
interface Props { interface Props {
requestHeaders: any; requestHeaders: Record<string,string>
responseHeaders: any; responseHeaders: Record<string,string>
} }
function Headers(props: Props) { function Headers(props: Props) {
return ( return (
@ -21,7 +21,7 @@ function Headers(props: Props) {
show={!props.requestHeaders && !props.responseHeaders} show={!props.requestHeaders && !props.responseHeaders}
// animatedIcon="no-results" // animatedIcon="no-results"
> >
{props.requestHeaders && ( {props.requestHeaders && Object.values(props.requestHeaders).length > 0 && (
<> <>
<div className="mb-4 mt-4"> <div className="mb-4 mt-4">
<div className="my-2 font-medium">Request Headers</div> <div className="my-2 font-medium">Request Headers</div>
@ -36,7 +36,7 @@ function Headers(props: Props) {
</> </>
)} )}
{props.responseHeaders && ( {props.responseHeaders && Object.values(props.responseHeaders).length > 0 && (
<div className="mt-4"> <div className="mt-4">
<div className="my-2 font-medium">Response Headers</div> <div className="my-2 font-medium">Response Headers</div>
{Object.keys(props.responseHeaders).map((h) => ( {Object.keys(props.responseHeaders).map((h) => (

View file

@ -228,9 +228,12 @@ export default class MessageManager {
let fileReadPromise = this.session.domURL && this.session.domURL.length > 0 let fileReadPromise = this.session.domURL && this.session.domURL.length > 0
? loadFiles(this.session.domURL, createNewParser()) ? loadFiles(this.session.domURL, createNewParser())
: requestEFSDom(this.session.sessionId) : Promise.reject()
.then(createNewParser(false)) fileReadPromise
fileReadPromise.catch(e => { // EFS fallback
.catch(() => requestEFSDom(this.session.sessionId).then(createNewParser(false)))
// old url fallback
.catch(e => {
logger.error('Can not get normal session replay file:', e) logger.error('Can not get normal session replay file:', e)
// back compat fallback to an old mobsUrl // back compat fallback to an old mobsUrl
return loadFiles(this.session.mobsUrl, createNewParser(false)) return loadFiles(this.session.mobsUrl, createNewParser(false))

View file

@ -115,12 +115,8 @@ export default Record(
.filter(({ type, time }) => type !== TYPES.CONSOLE && time <= durationSeconds); .filter(({ type, time }) => type !== TYPES.CONSOLE && time <= durationSeconds);
let resources = List(session.resources).map(Resource); let resources = List(session.resources).map(Resource);
// this code shoud die.
const firstResourceTime = resources
.map((r) => r.time)
.reduce((a, b) => Math.min(a, b), Number.MAX_SAFE_INTEGER);
resources = resources resources = resources
.map((r) => r.set('time', r.time - firstResourceTime)) .map((r) => r.set('time', Math.max(0, r.time - startedAt)))
.sort((r1, r2) => r1.time - r2.time); .sort((r1, r2) => r1.time - r2.time);
const missedResources = resources.filter(({ success }) => !success); const missedResources = resources.filter(({ success }) => !success);
@ -171,7 +167,6 @@ export default Record(
), ),
userDisplayName: userDisplayName:
session.userId || session.userAnonymousId || session.userID || 'Anonymous User', session.userId || session.userAnonymousId || session.userID || 'Anonymous User',
firstResourceTime,
issues: issuesList, issues: issuesList,
sessionId: sessionId || sessionID, sessionId: sessionId || sessionID,
userId: session.userId || session.userID, userId: session.userId || session.userID,

View file

@ -17,7 +17,7 @@ export function debounce(callback, wait, context = this) {
}; };
} }
export function getResourceName(url = '') { export function getResourceName(url: string) {
return url return url
.split('/') .split('/')
.filter((s) => s !== '') .filter((s) => s !== '')