feat(frontend):maintain new NetworkRequest message & fix request/response payload view & fix sess files download logic
This commit is contained in:
parent
f37757f2d2
commit
b819e86945
5 changed files with 72 additions and 58 deletions
|
|
@ -29,6 +29,7 @@ const OTHER = 'other';
|
|||
|
||||
const TYPE_TO_TAB = {
|
||||
[TYPES.XHR]: XHR,
|
||||
[TYPES.FETCH]: XHR,
|
||||
[TYPES.JS]: JS,
|
||||
[TYPES.CSS]: CSS,
|
||||
[TYPES.IMG]: IMG,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,11 @@ const REQUEST = 'REQUEST';
|
|||
const RESPONSE = 'RESPONSE';
|
||||
const TABS = [HEADERS, REQUEST, RESPONSE].map((tab) => ({ text: tab, key: tab }));
|
||||
|
||||
|
||||
function isValidJSON(o: any): o is Object {
|
||||
return typeof o === "object" && o != null
|
||||
}
|
||||
|
||||
interface Props {
|
||||
resource: any;
|
||||
}
|
||||
|
|
@ -15,37 +20,41 @@ function FetchTabs(props: Props) {
|
|||
const { resource } = props;
|
||||
const [activeTab, setActiveTab] = useState(HEADERS);
|
||||
const onTabClick = (tab: string) => setActiveTab(tab);
|
||||
const [jsonPayload, setJsonPayload] = useState(null);
|
||||
const [jsonResponse, setJsonResponse] = useState(null);
|
||||
const [jsonRequest, setJsonRequest] = useState<Object | string | null>(null);
|
||||
const [jsonResponse, setJsonResponse] = useState<Object | string | null>(null);
|
||||
const [requestHeaders, setRequestHeaders] = useState(null);
|
||||
const [responseHeaders, setResponseHeaders] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const { payload, response } = resource;
|
||||
const { request, response } = resource;
|
||||
|
||||
try {
|
||||
let jsonPayload = typeof payload === 'string' ? JSON.parse(payload) : payload;
|
||||
let requestHeaders = jsonPayload.headers;
|
||||
jsonPayload.body =
|
||||
typeof jsonPayload.body === 'string' ? JSON.parse(jsonPayload.body) : jsonPayload.body;
|
||||
delete jsonPayload.headers;
|
||||
setJsonPayload(jsonPayload);
|
||||
setRequestHeaders(requestHeaders);
|
||||
} catch (e) {}
|
||||
let jRequest = JSON.parse(request)
|
||||
setRequestHeaders(jRequest.headers);
|
||||
try {
|
||||
let jBody = JSON.parse(jRequest.body)
|
||||
jBody = isValidJSON(jBody) ? jBody : jRequest.body
|
||||
setJsonRequest(jBody)
|
||||
} catch {
|
||||
setJsonRequest(jRequest.body)
|
||||
}
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
let jsonResponse = typeof response === 'string' ? JSON.parse(response) : response;
|
||||
let responseHeaders = jsonResponse.headers;
|
||||
jsonResponse.body =
|
||||
typeof jsonResponse.body === 'string' ? JSON.parse(jsonResponse.body) : jsonResponse.body;
|
||||
delete jsonResponse.headers;
|
||||
setJsonResponse(jsonResponse);
|
||||
setResponseHeaders(responseHeaders);
|
||||
} catch (e) {}
|
||||
}, [resource, activeTab]);
|
||||
let jResponse = JSON.parse(response)
|
||||
setResponseHeaders(jResponse.headers);
|
||||
try {
|
||||
let jBody = JSON.parse(jResponse.body)
|
||||
jBody = isValidJSON(jBody) ? jBody : jResponse.body
|
||||
setJsonResponse(jBody)
|
||||
} catch {
|
||||
setJsonResponse(jResponse.body)
|
||||
}
|
||||
} catch {}
|
||||
}, [resource]);
|
||||
|
||||
const renderActiveTab = () => {
|
||||
const { payload, response } = resource;
|
||||
const { request, response } = resource;
|
||||
switch (activeTab) {
|
||||
case REQUEST:
|
||||
return (
|
||||
|
|
@ -57,15 +66,15 @@ function FetchTabs(props: Props) {
|
|||
</div>
|
||||
}
|
||||
size="small"
|
||||
show={!payload}
|
||||
show={!request}
|
||||
// animatedIcon="no-results"
|
||||
>
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
{jsonPayload === undefined ? (
|
||||
<div className="ml-3 break-words my-3"> {payload} </div>
|
||||
{ !isValidJSON(jsonRequest) ? (
|
||||
<div className="ml-3 break-words my-3"> {jsonRequest || request} </div>
|
||||
) : (
|
||||
<JSONTree src={jsonPayload} collapsed={false} enableClipboard />
|
||||
<JSONTree src={jsonRequest} collapsed={false} enableClipboard />
|
||||
)}
|
||||
</div>
|
||||
<div className="divider" />
|
||||
|
|
@ -87,8 +96,8 @@ function FetchTabs(props: Props) {
|
|||
>
|
||||
<div>
|
||||
<div className="mt-6">
|
||||
{jsonResponse === undefined ? (
|
||||
<div className="ml-3 break-words my-3"> {response} </div>
|
||||
{ !isValidJSON(jsonResponse) ? (
|
||||
<div className="ml-3 break-words my-3"> {jsonResponse || response} </div>
|
||||
) : (
|
||||
<JSONTree src={jsonResponse} collapsed={false} enableClipboard />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@ export default class ListWalker<T extends Timed> {
|
|||
this.list.push(m);
|
||||
}
|
||||
|
||||
insert(m: T): void {
|
||||
let index = this.list.findIndex(om => om.time > m.time)
|
||||
if (index === -1) {
|
||||
index = this.length
|
||||
}
|
||||
const oldList = this.list
|
||||
this._list = [...oldList.slice(0, index), m, ...oldList.slice(index)]
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.p = 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
import { Decoder } from "syncod";
|
||||
import logger from 'App/logger';
|
||||
|
||||
import Resource, { TYPES } from 'Types/session/resource';
|
||||
import Resource, { TYPES as RES_TYPES } from 'Types/session/resource';
|
||||
import { TYPES as EVENT_TYPES } from 'Types/session/event';
|
||||
import { Log } from './types';
|
||||
|
||||
|
|
@ -187,13 +187,12 @@ export default class MessageManager {
|
|||
const stateToUpdate : Partial<State>= {
|
||||
performanceChartData: this.performanceTrackManager.chartData,
|
||||
performanceAvaliability: this.performanceTrackManager.avaliability,
|
||||
...this.lists.getFullListsState()
|
||||
...this.lists.getFullListsState(),
|
||||
}
|
||||
if (this.activityManager) {
|
||||
this.activityManager.end()
|
||||
stateToUpdate.skipIntervals = this.activityManager.list
|
||||
}
|
||||
|
||||
this.state.update(stateToUpdate)
|
||||
}
|
||||
private onFileReadFailed = (e: any) => {
|
||||
|
|
@ -227,26 +226,18 @@ export default class MessageManager {
|
|||
this.setMessagesLoading(true)
|
||||
this.waitingForFiles = true
|
||||
|
||||
try {
|
||||
if (this.session.domURL && this.session.domURL.length > 0) {
|
||||
await loadFiles(this.session.domURL, createNewParser())
|
||||
this.onFileReadSuccess()
|
||||
} else {
|
||||
const file = await requestEFSDom(this.session.sessionId)
|
||||
const parser = createNewParser(false)
|
||||
await parser(file)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Cant get session replay file:', e)
|
||||
try {
|
||||
// back compat with old mobsUrl
|
||||
await loadFiles(this.session.mobsUrl, createNewParser(false))
|
||||
} catch (e) {
|
||||
this.onFileReadFailed(e)
|
||||
}
|
||||
} finally {
|
||||
this.onFileReadFinally()
|
||||
}
|
||||
let fileReadPromise = this.session.domURL && this.session.domURL.length > 0
|
||||
? loadFiles(this.session.domURL, createNewParser())
|
||||
: requestEFSDom(this.session.sessionId)
|
||||
.then(createNewParser(false))
|
||||
fileReadPromise.catch(e => {
|
||||
logger.error('Can not get normal session replay file:', e)
|
||||
// back compat fallback to an old mobsUrl
|
||||
return loadFiles(this.session.mobsUrl, createNewParser(false))
|
||||
})
|
||||
.then(this.onFileReadSuccess)
|
||||
.catch(this.onFileReadFailed)
|
||||
.finally(this.onFileReadFinally)
|
||||
|
||||
// load devtools
|
||||
if (this.session.devtoolsURL.length) {
|
||||
|
|
@ -256,7 +247,10 @@ export default class MessageManager {
|
|||
requestEFSDevtools(this.session.sessionId)
|
||||
.then(createNewParser(false))
|
||||
)
|
||||
//.catch() // not able to download the devtools file
|
||||
.then(() => {
|
||||
this.state.update(this.lists.getFullListsState())
|
||||
})
|
||||
.catch(e => logger.error("Can not download the devtools file", e))
|
||||
.finally(() => this.state.update({ devtoolsLoading: false }))
|
||||
}
|
||||
}
|
||||
|
|
@ -439,15 +433,16 @@ export default class MessageManager {
|
|||
)
|
||||
break;
|
||||
case MType.Fetch:
|
||||
case MType.NetworkRequest:
|
||||
// @ts-ignore burn immutable
|
||||
this.lists.lists.fetch.append(Resource({
|
||||
this.lists.lists.fetch.insert(Resource({
|
||||
method: msg.method,
|
||||
url: msg.url,
|
||||
payload: msg.request,
|
||||
request: msg.request,
|
||||
response: msg.response,
|
||||
status: msg.status,
|
||||
duration: msg.duration,
|
||||
type: TYPES.XHR,
|
||||
type: msg.type === "xhr" ? RES_TYPES.XHR : RES_TYPES.FETCH,
|
||||
time: Math.max(msg.timestamp - this.sessionStart, 0), // !!! doesn't look good. TODO: find solution to show negative timings
|
||||
index,
|
||||
}) as Timed)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Record from 'Types/Record';
|
|||
import { getResourceName } from 'App/utils';
|
||||
|
||||
const XHR = 'xhr';
|
||||
const FETCH = 'fetch';
|
||||
const JS = 'script';
|
||||
const CSS = 'css';
|
||||
const IMG = 'img';
|
||||
|
|
@ -32,7 +33,6 @@ const OTHER = 'other';
|
|||
|
||||
const TYPES_MAP = {
|
||||
"stylesheet": CSS,
|
||||
"fetch": XHR,
|
||||
}
|
||||
|
||||
function getResourceStatus(status, success) {
|
||||
|
|
@ -53,6 +53,7 @@ function getResourceSuccess(success, status) {
|
|||
|
||||
export const TYPES = {
|
||||
XHR,
|
||||
FETCH,
|
||||
JS,
|
||||
CSS,
|
||||
IMG,
|
||||
|
|
@ -85,7 +86,7 @@ export default Record({
|
|||
// initiator: "other",
|
||||
// pagePath: "",
|
||||
method: '',
|
||||
payload:'',
|
||||
request:'',
|
||||
response: '',
|
||||
headerSize: 0,
|
||||
encodedBodySize: 0,
|
||||
|
|
@ -93,14 +94,13 @@ export default Record({
|
|||
responseBodySize: 0,
|
||||
timings: List(),
|
||||
}, {
|
||||
fromJS: ({ responseBody, response, type, initiator, status, success, time, datetime, timestamp, timings, ...resource }) => ({
|
||||
fromJS: ({ type, initiator, status, success, time, datetime, timestamp, timings, ...resource }) => ({
|
||||
...resource,
|
||||
type: TYPES_MAP[type] || type,
|
||||
name: getResourceName(resource.url),
|
||||
status: getResourceStatus(status, success),
|
||||
success: getResourceSuccess(success, status),
|
||||
time: typeof time === 'number' ? time : datetime || timestamp,
|
||||
response: responseBody || response,
|
||||
ttfb: timings && timings.ttfb,
|
||||
timewidth: timings && timings.timewidth,
|
||||
timings,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue