diff --git a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx
index 685b219bf..6cb6b66bc 100644
--- a/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx
+++ b/frontend/app/components/shared/DevTools/NetworkPanel/NetworkPanel.tsx
@@ -67,36 +67,36 @@ export function renderStart(r: any) {
);
}
-const renderXHRText = () => (
-
- {XHR}
-
- Use our{' '}
-
- Fetch plugin
-
- {' to capture HTTP requests and responses, including status codes and bodies.'}
- We also provide{' '}
-
- support for GraphQL
-
- {' for easy debugging of your queries.'}
- >
- }
- className="ml-1"
- />
-
-);
+// const renderXHRText = () => (
+//
+// {XHR}
+//
+// Use our{' '}
+//
+// Fetch plugin
+//
+// {' to capture HTTP requests and responses, including status codes and bodies.'}
+// We also provide{' '}
+//
+// support for GraphQL
+//
+// {' for easy debugging of your queries.'}
+// >
+// }
+// className="ml-1"
+// />
+//
+// );
function renderSize(r: any) {
if (r.responseBodySize) return formatBytes(r.responseBodySize);
@@ -180,6 +180,7 @@ function NetworkPanel(props: Props) {
const [sortAscending, setSortAscending] = useState(true);
const [filter, setFilter] = useState('');
const [showOnlyErrors, setShowOnlyErrors] = useState(false);
+ const [activeRequest, setActiveRequest] = useState(false )
const onTabClick = (activeTab: any) => setActiveTab(activeTab);
const onFilterChange = ({ target: { value } }: any) => setFilter(value);
const additionalHeight = 0;
@@ -237,7 +238,7 @@ function NetworkPanel(props: Props) {
}
const onRowClick = (row: any) => {
- showModal(, {
+ showModal(, {
right: true,
});
};
diff --git a/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.js b/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.js
deleted file mode 100644
index 1f7b21a1d..000000000
--- a/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.js
+++ /dev/null
@@ -1,257 +0,0 @@
-import React from 'react';
-import { JSONTree, NoContent, Button, Tabs, Icon } from 'UI';
-import cn from 'classnames';
-import stl from './fetchDetails.module.css';
-import Headers from './components/Headers';
-import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
-import { TYPES } from 'Types/session/resource';
-import { formatBytes } from 'App/utils';
-import CopyText from 'Shared/CopyText';
-
-const HEADERS = 'HEADERS';
-const REQUEST = 'REQUEST';
-const RESPONSE = 'RESPONSE';
-
-const TABS = [HEADERS, REQUEST, RESPONSE].map((tab) => ({ text: tab, key: tab }));
-
-export default class FetchDetailsModal extends React.PureComponent {
- state = { activeTab: REQUEST, tabs: [] };
-
- onTabClick = (activeTab) => this.setState({ activeTab });
-
- componentDidMount() {
- this.checkTabs();
- }
-
- renderActiveTab = (tab) => {
- const {
- resource: { payload, response = this.props.resource.body },
- } = this.props;
- let jsonPayload,
- jsonResponse,
- requestHeaders,
- responseHeaders = undefined;
-
- try {
- jsonPayload = typeof payload === 'string' ? JSON.parse(payload) : payload;
- requestHeaders = jsonPayload.headers;
- jsonPayload.body =
- typeof jsonPayload.body === 'string' ? JSON.parse(jsonPayload.body) : jsonPayload.body;
- delete jsonPayload.headers;
- } catch (e) {}
-
- try {
- jsonResponse = typeof response === 'string' ? JSON.parse(response) : response;
- responseHeaders = jsonResponse.headers;
- jsonResponse.body =
- typeof jsonResponse.body === 'string' ? JSON.parse(jsonResponse.body) : jsonResponse.body;
- delete jsonResponse.headers;
- } catch (e) {}
-
- switch (tab) {
- case REQUEST:
- return (
-
-
- Body is Empty.
-
- }
- size="small"
- show={!payload}
- // animatedIcon="no-results"
- >
-
-
- {jsonPayload === undefined ? (
-
{payload}
- ) : (
-
- )}
-
-
-
-
- );
- case RESPONSE:
- return (
-
-
- Body is Empty.
-
- }
- size="small"
- show={!response}
- // animatedIcon="no-results"
- >
-
-
- {jsonResponse === undefined ? (
-
{response}
- ) : (
-
- )}
-
-
-
-
- );
- case HEADERS:
- return ;
- }
- };
-
- componentDidUpdate(prevProps) {
- if (prevProps.resource.index === this.props.resource.index) return;
-
- this.checkTabs();
- }
-
- checkTabs() {
- const {
- resource: { payload, response, body },
- isResult,
- } = this.props;
- const _tabs = TABS;
- // const _tabs = TABS.filter(t => {
- // if (t.key == REQUEST && !!payload) {
- // return true
- // }
-
- // if (t.key == RESPONSE && !!response) {
- // return true;
- // }
-
- // return false;
- // })
- this.setState({ tabs: _tabs, activeTab: _tabs.length > 0 ? _tabs[0].key : null });
- }
-
- render() {
- const {
- resource,
- fetchPresented,
- nextClick,
- prevClick,
- first = false,
- last = false,
- } = this.props;
- const { method, url, duration } = resource;
- const { activeTab, tabs } = this.state;
- const _duration = parseInt(duration);
-
- return (
-
-
Network Request
-
-
Name
-
- {resource.name}
-
-
-
-
-
Type
-
- {resource.type}
-
-
-
- {!!resource.decodedBodySize && (
-
-
Size
-
- {formatBytes(resource.decodedBodySize)}
-
-
- )}
-
- {method && (
-
-
Request Method
-
- {resource.method}
-
-
- )}
-
- {resource.status && (
-
-
Status
-
- {resource.status === '200' && (
-
- )}
- {resource.status}
-
-
- )}
-
- {!!_duration && (
-
-
Time
-
- {_duration} ms
-
-
- )}
-
- {resource.type === TYPES.XHR && !fetchPresented && (
-
-
-
- Get more out of network requests
-
-
- -
- Integrate{' '}
-
- Fetch plugin
- {' '}
- to capture fetch payloads.
-
- -
- Find a detailed{' '}
-
- video tutorial
- {' '}
- to understand practical example of how to use fetch plugin.
-
-
-
- )}
-
-
- {resource.type === TYPES.XHR && fetchPresented && (
-
-
-
- {this.renderActiveTab(activeTab)}
-
-
- )}
-
- {/*
-
-
-
*/}
-
-
- );
- }
-}
diff --git a/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.tsx b/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.tsx
new file mode 100644
index 000000000..8ae23e0f4
--- /dev/null
+++ b/frontend/app/components/shared/FetchDetailsModal/FetchDetailsModal.tsx
@@ -0,0 +1,63 @@
+import React, { useEffect, useState } from 'react';
+import FetchBasicDetails from './components/FetchBasicDetails';
+import { Button } from 'UI';
+import FetchPluginMessage from './components/FetchPluginMessage';
+import { TYPES } from 'Types/session/resource';
+import FetchTabs from './components/FetchTabs/FetchTabs';
+
+interface Props {
+ resource: any;
+ rows: any;
+ fetchPresented?: boolean;
+}
+function FetchDetailsModal(props: Props) {
+ const { rows, fetchPresented = false } = props;
+ const [resource, setResource] = useState(props.resource);
+ const [first, setFirst] = useState(false);
+ const [last, setLast] = useState(false);
+
+ useEffect(() => {
+ const index = rows.indexOf(resource);
+ const length = rows.length - 1;
+ setFirst(index === 0);
+ setLast(index === length);
+ }, [resource]);
+
+ const prevClick = () => {
+ const index = rows.indexOf(resource);
+ if (index > 0) {
+ setResource(rows[index - 1]);
+ }
+ };
+
+ const nextClick = () => {
+ const index = rows.indexOf(resource);
+ if (index < rows.length - 1) {
+ setResource(rows[index + 1]);
+ }
+ };
+
+ return (
+
+
Network Request
+
+
+ {resource.type === TYPES.XHR && !fetchPresented &&
}
+
+ {resource.type === TYPES.XHR && fetchPresented &&
}
+
+ {rows && rows.length > 0 && (
+
+
+
+
+ )}
+
+ );
+}
+
+export default FetchDetailsModal;
diff --git a/frontend/app/components/shared/FetchDetailsModal/components/FetchBasicDetails/FetchBasicDetails.tsx b/frontend/app/components/shared/FetchDetailsModal/components/FetchBasicDetails/FetchBasicDetails.tsx
new file mode 100644
index 000000000..6c81a744c
--- /dev/null
+++ b/frontend/app/components/shared/FetchDetailsModal/components/FetchBasicDetails/FetchBasicDetails.tsx
@@ -0,0 +1,70 @@
+import React from 'react';
+import { Icon } from 'UI';
+import { formatBytes } from 'App/utils';
+import CopyText from 'Shared/CopyText';
+import { TYPES } from 'Types/session/resource';
+
+interface Props {
+ resource: any;
+}
+function FetchBasicDetails({ resource }: Props) {
+ const _duration = parseInt(resource.duration);
+ return (
+
+
+
Name
+
+ {resource.name}
+
+
+
+
+
Type
+
+ {resource.type}
+
+
+
+ {!!resource.decodedBodySize && (
+
+
Size
+
+ {formatBytes(resource.decodedBodySize)}
+
+
+ )}
+
+ {resource.method && (
+
+
Request Method
+
+ {resource.method}
+
+
+ )}
+
+ {resource.status && (
+
+
Status
+
+ {resource.status === '200' && (
+
+ )}
+ {resource.status}
+
+
+ )}
+
+ {!!_duration && (
+
+
Time
+
+ {_duration} ms
+
+
+ )}
+
+ );
+}
+
+export default FetchBasicDetails;
diff --git a/frontend/app/components/shared/FetchDetailsModal/components/FetchBasicDetails/index.ts b/frontend/app/components/shared/FetchDetailsModal/components/FetchBasicDetails/index.ts
new file mode 100644
index 000000000..86f95ff45
--- /dev/null
+++ b/frontend/app/components/shared/FetchDetailsModal/components/FetchBasicDetails/index.ts
@@ -0,0 +1 @@
+export { default } from './FetchBasicDetails';
diff --git a/frontend/app/components/shared/FetchDetailsModal/components/FetchPluginMessage/FetchPluginMessage.tsx b/frontend/app/components/shared/FetchDetailsModal/components/FetchPluginMessage/FetchPluginMessage.tsx
new file mode 100644
index 000000000..8699b8cb6
--- /dev/null
+++ b/frontend/app/components/shared/FetchDetailsModal/components/FetchPluginMessage/FetchPluginMessage.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Icon } from 'UI';
+
+function FetchPluginMessage() {
+ return (
+
+
+
+ Get more out of network requests
+
+
+ -
+ Integrate{' '}
+
+ Fetch plugin
+ {' '}
+ to capture fetch payloads.
+
+ -
+ Find a detailed{' '}
+
+ video tutorial
+ {' '}
+ to understand practical example of how to use fetch plugin.
+
+
+
+ );
+}
+
+export default FetchPluginMessage;
diff --git a/frontend/app/components/shared/FetchDetailsModal/components/FetchPluginMessage/index.ts b/frontend/app/components/shared/FetchDetailsModal/components/FetchPluginMessage/index.ts
new file mode 100644
index 000000000..df224dbbf
--- /dev/null
+++ b/frontend/app/components/shared/FetchDetailsModal/components/FetchPluginMessage/index.ts
@@ -0,0 +1 @@
+export { default } from './FetchPluginMessage';
diff --git a/frontend/app/components/shared/FetchDetailsModal/components/FetchTabs/FetchTabs.tsx b/frontend/app/components/shared/FetchDetailsModal/components/FetchTabs/FetchTabs.tsx
new file mode 100644
index 000000000..837a61ec6
--- /dev/null
+++ b/frontend/app/components/shared/FetchDetailsModal/components/FetchTabs/FetchTabs.tsx
@@ -0,0 +1,112 @@
+import React, { useEffect, useState } from 'react';
+import Headers from '../Headers';
+import { JSONTree, Tabs, NoContent } from 'UI';
+import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
+
+const HEADERS = 'HEADERS';
+const REQUEST = 'REQUEST';
+const RESPONSE = 'RESPONSE';
+const TABS = [HEADERS, REQUEST, RESPONSE].map((tab) => ({ text: tab, key: tab }));
+
+interface Props {
+ resource: any;
+}
+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 [requestHeaders, setRequestHeaders] = useState(null);
+ const [responseHeaders, setResponseHeaders] = useState(null);
+
+ useEffect(() => {
+ const { payload, 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) {}
+
+ 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]);
+
+ const renderActiveTab = () => {
+ const { payload, response } = resource;
+ switch (activeTab) {
+ case REQUEST:
+ return (
+
+
+ Body is Empty.
+
+ }
+ size="small"
+ show={!payload}
+ // animatedIcon="no-results"
+ >
+
+
+ {jsonPayload === undefined ? (
+
{payload}
+ ) : (
+
+ )}
+
+
+
+
+ );
+ case RESPONSE:
+ return (
+
+
+ Body is Empty.
+
+ }
+ size="small"
+ show={!response}
+ // animatedIcon="no-results"
+ >
+
+
+ {jsonResponse === undefined ? (
+
{response}
+ ) : (
+
+ )}
+
+
+
+
+ );
+ case HEADERS:
+ return ;
+ }
+ };
+ return (
+
+
+
{renderActiveTab()}
+
+ );
+}
+
+export default FetchTabs;
diff --git a/frontend/app/components/shared/FetchDetailsModal/components/Headers/Headers.tsx b/frontend/app/components/shared/FetchDetailsModal/components/Headers/Headers.tsx
index c2ec31a07..78c4a5e64 100644
--- a/frontend/app/components/shared/FetchDetailsModal/components/Headers/Headers.tsx
+++ b/frontend/app/components/shared/FetchDetailsModal/components/Headers/Headers.tsx
@@ -1,9 +1,13 @@
-import React from 'react'
-import { NoContent, TextEllipsis } from 'UI'
-import stl from './headers.module.css'
+import React from 'react';
+import { NoContent, TextEllipsis } from 'UI';
+import stl from './headers.module.css';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
-function Headers(props) {
+interface Props {
+ requestHeaders: any;
+ responseHeaders: any;
+}
+function Headers(props: Props) {
return (
}
size="small"
- show={ !props.requestHeaders && !props.responseHeaders }
+ show={!props.requestHeaders && !props.responseHeaders}
// animatedIcon="no-results"
>
- { props.requestHeaders && (
+ {props.requestHeaders && (
<>
Request Headers
- {
- Object.keys(props.requestHeaders).map(h => (
-
- {h}:
- {props.requestHeaders[h]}
-
- ))
- }
+ {Object.keys(props.requestHeaders).map((h) => (
+
+ {h}:
+ {props.requestHeaders[h]}
+
+ ))}
>
)}
-
- { props.responseHeaders && (
+
+ {props.responseHeaders && (
Response Headers
- {
- Object.keys(props.responseHeaders).map(h => (
-
- {h}:
- {props.responseHeaders[h]}
-
- ))
- }
+ {Object.keys(props.responseHeaders).map((h) => (
+
+ {h}:
+ {props.responseHeaders[h]}
+
+ ))}
)}
@@ -52,4 +52,4 @@ function Headers(props) {
);
}
-export default Headers;
\ No newline at end of file
+export default Headers;
diff --git a/frontend/app/components/ui/Tabs/Tabs.js b/frontend/app/components/ui/Tabs/Tabs.js
index cd9921161..248dae3dd 100644
--- a/frontend/app/components/ui/Tabs/Tabs.js
+++ b/frontend/app/components/ui/Tabs/Tabs.js
@@ -2,7 +2,7 @@ import React from 'react';
import cn from 'classnames';
import stl from './tabs.module.css';
-const Tabs = ({ tabs, active, onClick, border = true, className }) => (
+const Tabs = ({ tabs, active, onClick, border = true, className = '' }) => (
{ tabs.map(({ key, text, hidden = false, disabled = false }) => (