mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-07-31 00:04:43 +00:00
Bring in the necessary changes from f74a52d4dc
This commit is contained in:
parent
ffc7e05b44
commit
4709bae0ee
12
README.md
12
README.md
@ -159,3 +159,15 @@ Such validation may test response for specific JSON fields, headers, etc.
|
||||
|
||||
Please see [API RULES](docs/POLICY_RULES.md) page for more details and syntax.
|
||||
|
||||
|
||||
## How to Run local UI
|
||||
|
||||
- run from mizu/agent `go run main.go --hars-read --hars-dir <folder>`
|
||||
|
||||
- copy Har files into the folder from last command
|
||||
|
||||
- change `MizuWebsocketURL` and `apiURL` in `api.js` file
|
||||
|
||||
- run from mizu/ui - `npm run start`
|
||||
|
||||
- open browser on `localhost:3000`
|
||||
|
@ -32,6 +32,8 @@ var apiServerMode = flag.Bool("api-server", false, "Run in API server mode with
|
||||
var standaloneMode = flag.Bool("standalone", false, "Run in standalone tapper and API mode")
|
||||
var apiServerAddress = flag.String("api-server-address", "", "Address of mizu API server")
|
||||
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
|
||||
var harsReaderMode = flag.Bool("hars-read", false, "Run in hars-read mode")
|
||||
var harsDir = flag.String("hars-dir", "", "Directory to read hars from")
|
||||
|
||||
var extensions []*tapApi.Extension // global
|
||||
var extensionsMap map[string]*tapApi.Extension // global
|
||||
@ -43,8 +45,8 @@ func main() {
|
||||
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
||||
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
||||
|
||||
if !*tapperMode && !*apiServerMode && !*standaloneMode {
|
||||
panic("One of the flags --tap, --api or --standalone must be provided")
|
||||
if !*tapperMode && !*apiServerMode && !*standaloneMode && !*harsReaderMode {
|
||||
panic("One of the flags --tap, --api or --standalone or --hars-read must be provided")
|
||||
}
|
||||
|
||||
if *standaloneMode {
|
||||
@ -90,6 +92,13 @@ func main() {
|
||||
go api.StartReadingEntries(socketHarOutChannel, nil, extensionsMap)
|
||||
|
||||
hostApi(socketHarOutChannel)
|
||||
} else if *harsReaderMode {
|
||||
socketHarOutChannel := make(chan *tapApi.OutputChannelItem, 1000)
|
||||
// filteredHarChannel := make(chan *tap.OutputChannelItem)
|
||||
|
||||
// go filterHarItems(socketHarOutChannel, filteredHarChannel, getTrafficFilteringOptions())
|
||||
go api.StartReadingEntries(socketHarOutChannel, harsDir, extensionsMap)
|
||||
hostApi(nil)
|
||||
}
|
||||
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
|
@ -1,4 +1,4 @@
|
||||
@import 'components/style/variables.module'
|
||||
@import './variables.module'
|
||||
|
||||
.mizuApp
|
||||
background-color: $main-background-color
|
||||
@ -22,4 +22,4 @@
|
||||
margin-left: 10px
|
||||
font-size: 11px
|
||||
font-weight: bold
|
||||
color: $light-blue-color
|
||||
color: $light-blue-color
|
||||
|
@ -2,8 +2,8 @@ import React, {useEffect, useState} from 'react';
|
||||
import './App.sass';
|
||||
import logo from './components/assets/Mizu-logo.svg';
|
||||
import {Button, Snackbar} from "@material-ui/core";
|
||||
import {HarPage} from "./components/HarPage";
|
||||
import Tooltip from "./components/Tooltip";
|
||||
import {TrafficPage} from "./components/TrafficPage";
|
||||
import Tooltip from "./components/UI/Tooltip";
|
||||
import {makeStyles} from "@material-ui/core/styles";
|
||||
import MuiAlert from '@material-ui/lab/Alert';
|
||||
import Api from "./helpers/api";
|
||||
@ -116,7 +116,7 @@ const App = () => {
|
||||
</Tooltip>
|
||||
}
|
||||
</div>
|
||||
<HarPage setAnalyzeStatus={setAnalyzeStatus} onTLSDetected={onTLSDetected}/>
|
||||
<TrafficPage setAnalyzeStatus={setAnalyzeStatus} onTLSDetected={onTLSDetected}/>
|
||||
<Snackbar open={showTLSWarning && !userDismissedTLSWarning}>
|
||||
<MuiAlert elevation={6} variant="filled" onClose={() => setUserDismissedTLSWarning(true)} severity="warning">
|
||||
Mizu is detecting TLS traffic{addressesWithTLS.size ? ` (directed to ${Array.from(addressesWithTLS).join(", ")})` : ''}, this type of traffic will not be displayed.
|
||||
|
@ -1,13 +1,13 @@
|
||||
import {HarEntry} from "./HarEntry";
|
||||
import React, {useCallback, useEffect, useMemo, useState} from "react";
|
||||
import styles from './style/HarEntriesList.module.sass';
|
||||
import {EntryItem} from "./EntryListItem/EntryListItem";
|
||||
import React, {useCallback, useEffect, useMemo, useRef, useState} from "react";
|
||||
import styles from './style/EntriesList.module.sass';
|
||||
import spinner from './assets/spinner.svg';
|
||||
import ScrollableFeed from "react-scrollable-feed";
|
||||
import {StatusType} from "./HarFilters";
|
||||
import {StatusType} from "./Filters";
|
||||
import Api from "../helpers/api";
|
||||
import uninon from "./assets/union.svg";
|
||||
import down from "./assets/downImg.svg";
|
||||
|
||||
interface HarEntriesListProps {
|
||||
interface EntriesListProps {
|
||||
entries: any[];
|
||||
setEntries: (entries: any[]) => void;
|
||||
focusedEntryId: string;
|
||||
@ -32,11 +32,13 @@ enum FetchOperator {
|
||||
|
||||
const api = new Api();
|
||||
|
||||
export const HarEntriesList: React.FC<HarEntriesListProps> = ({entries, setEntries, focusedEntryId, setFocusedEntryId, connectionOpen, noMoreDataTop, setNoMoreDataTop, noMoreDataBottom, setNoMoreDataBottom, methodsFilter, statusFilter, pathFilter, listEntryREF, onScrollEvent, scrollableList}) => {
|
||||
export const EntriesList: React.FC<EntriesListProps> = ({entries, setEntries, focusedEntryId, setFocusedEntryId, connectionOpen, noMoreDataTop, setNoMoreDataTop, noMoreDataBottom, setNoMoreDataBottom, methodsFilter, statusFilter, pathFilter, listEntryREF, onScrollEvent, scrollableList}) => {
|
||||
|
||||
const [loadMoreTop, setLoadMoreTop] = useState(false);
|
||||
const [isLoadingTop, setIsLoadingTop] = useState(false);
|
||||
|
||||
const scrollableRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const list = document.getElementById('list').firstElementChild;
|
||||
list.addEventListener('scroll', (e) => {
|
||||
@ -114,24 +116,20 @@ export const HarEntriesList: React.FC<HarEntriesListProps> = ({entries, setEntri
|
||||
{isLoadingTop && <div className={styles.spinnerContainer}>
|
||||
<img alt="spinner" src={spinner} style={{height: 25}}/>
|
||||
</div>}
|
||||
<ScrollableFeed onScroll={(isAtBottom) => onScrollEvent(isAtBottom)}>
|
||||
<ScrollableFeed ref={scrollableRef} onScroll={(isAtBottom) => onScrollEvent(isAtBottom)}>
|
||||
{noMoreDataTop && !connectionOpen && <div id="noMoreDataTop" className={styles.noMoreDataAvailable}>No more data available</div>}
|
||||
{filteredEntries.map(entry => <HarEntry key={entry.id}
|
||||
entry={entry}
|
||||
setFocusedEntryId={setFocusedEntryId}
|
||||
isSelected={focusedEntryId === entry.id}/>)}
|
||||
{filteredEntries.map(entry => <EntryItem key={entry.id}
|
||||
entry={entry}
|
||||
setFocusedEntryId={setFocusedEntryId}
|
||||
isSelected={focusedEntryId === entry.id}/>)}
|
||||
{!connectionOpen && !noMoreDataBottom && <div className={styles.fetchButtonContainer}>
|
||||
<div className={styles.styledButton} onClick={() => getNewEntries()}>Fetch more entries</div>
|
||||
</div>}
|
||||
</ScrollableFeed>
|
||||
<button type="button"
|
||||
className={`${styles.btnLive} ${scrollableList ? styles.showButton : styles.hideButton}`}
|
||||
onClick={(_) => {
|
||||
const list = listEntryREF.current.firstChild;
|
||||
if(list instanceof HTMLElement) {
|
||||
list.scrollTo({ top: list.scrollHeight, behavior: 'smooth' })
|
||||
}
|
||||
}}><img alt="Union" src={uninon} />
|
||||
onClick={(_) => scrollableRef.current.scrollToBottom()}>
|
||||
<img alt="down" src={down} />
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,10 +1,9 @@
|
||||
import React from "react";
|
||||
import {singleEntryToHAR} from "./utils";
|
||||
import HAREntryViewer from "./HarEntryViewer/HAREntryViewer";
|
||||
import EntryViewer from "./EntryDetailed/EntryViewer";
|
||||
import {makeStyles} from "@material-ui/core";
|
||||
import Protocol from "./Protocol"
|
||||
import StatusCode from "./StatusCode";
|
||||
import {EndpointPath} from "./EndpointPath";
|
||||
import Protocol from "./UI/Protocol"
|
||||
import StatusCode from "./UI/StatusCode";
|
||||
import {EndpointPath} from "./UI/EndpointPath";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
entryTitle: {
|
||||
@ -27,34 +26,32 @@ const useStyles = makeStyles(() => ({
|
||||
}
|
||||
}));
|
||||
|
||||
interface HarEntryDetailedProps {
|
||||
harEntry: any;
|
||||
classes?: any;
|
||||
interface EntryDetailedProps {
|
||||
entryData: any
|
||||
}
|
||||
|
||||
export const formatSize = (n: number) => n > 1000 ? `${Math.round(n / 1000)}KB` : `${n} B`;
|
||||
|
||||
const HarEntryTitle: React.FC<any> = ({protocol, har}) => {
|
||||
const EntryTitle: React.FC<any> = ({protocol, data}) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const {log: {entries}} = har;
|
||||
const {response} = JSON.parse(entries[0].entry);
|
||||
console.log("data:", data)
|
||||
const {response} = JSON.parse(data.entry);
|
||||
|
||||
|
||||
return <div className={classes.entryTitle}>
|
||||
<Protocol protocol={protocol} horizontal={true}/>
|
||||
<div style={{right: "30px", position: "absolute", display: "flex"}}>
|
||||
{response.payload && <div style={{margin: "0 18px", opacity: 0.5}}>{formatSize(response.payload.bodySize)}</div>}
|
||||
<div style={{opacity: 0.5}}>{'rulesMatched' in entries[0] ? entries[0].rulesMatched?.length : '0'} Rules Applied</div>
|
||||
<div style={{opacity: 0.5}}>{'rulesMatched' in data ? data.rulesMatched?.length : '0'} Rules Applied</div>
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
const HarEntrySummary: React.FC<any> = ({har}) => {
|
||||
const EntrySummary: React.FC<any> = ({data}) => {
|
||||
const classes = useStyles();
|
||||
|
||||
const {log: {entries}} = har;
|
||||
const {response, request} = JSON.parse(entries[0].entry);
|
||||
const {response, request} = JSON.parse(data.entry);
|
||||
|
||||
return <div className={classes.entrySummary}>
|
||||
{response?.payload && response.payload?.details && "status" in response.payload.details && <div style={{marginRight: 8}}>
|
||||
@ -66,14 +63,12 @@ const HarEntrySummary: React.FC<any> = ({har}) => {
|
||||
</div>;
|
||||
};
|
||||
|
||||
export const HAREntryDetailed: React.FC<HarEntryDetailedProps> = ({classes, harEntry}) => {
|
||||
const har = singleEntryToHAR(harEntry.data);
|
||||
|
||||
export const EntryDetailed: React.FC<EntryDetailedProps> = ({entryData}) => {
|
||||
return <>
|
||||
<HarEntryTitle protocol={harEntry.protocol} har={har}/>
|
||||
{har && <HarEntrySummary har={har}/>}
|
||||
<EntryTitle protocol={entryData.protocol} data={entryData.data}/>
|
||||
{entryData.data && <EntrySummary data={entryData.data}/>}
|
||||
<>
|
||||
{har && <HAREntryViewer representation={harEntry.representation} color={harEntry.protocol.background_color}/>}
|
||||
{entryData.data && <EntryViewer representation={entryData.representation} color={entryData.protocol.background_color}/>}
|
||||
</>
|
||||
</>
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
@import '../style/variables.module'
|
||||
@import '../../variables.module'
|
||||
|
||||
.title
|
||||
display: flex
|
@ -1,17 +1,17 @@
|
||||
import styles from "./HAREntrySections.module.sass";
|
||||
import styles from "./EntrySections.module.sass";
|
||||
import React, {useState} from "react";
|
||||
import {SyntaxHighlighter} from "../SyntaxHighlighter/index";
|
||||
import CollapsibleContainer from "../CollapsibleContainer";
|
||||
import FancyTextDisplay from "../FancyTextDisplay";
|
||||
import Checkbox from "../Checkbox";
|
||||
import {SyntaxHighlighter} from "../UI/SyntaxHighlighter/index";
|
||||
import CollapsibleContainer from "../UI/CollapsibleContainer";
|
||||
import FancyTextDisplay from "../UI/FancyTextDisplay";
|
||||
import Checkbox from "../UI/Checkbox";
|
||||
import ProtobufDecoder from "protobuf-decoder";
|
||||
|
||||
interface HAREntryViewLineProps {
|
||||
interface EntryViewLineProps {
|
||||
label: string;
|
||||
value: number | string;
|
||||
}
|
||||
|
||||
const HAREntryViewLine: React.FC<HAREntryViewLineProps> = ({label, value}) => {
|
||||
const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value}) => {
|
||||
return (label && value && <tr className={styles.dataLine}>
|
||||
<td className={styles.dataKey}>{label}</td>
|
||||
<td>
|
||||
@ -27,13 +27,13 @@ const HAREntryViewLine: React.FC<HAREntryViewLineProps> = ({label, value}) => {
|
||||
}
|
||||
|
||||
|
||||
interface HAREntrySectionCollapsibleTitleProps {
|
||||
interface EntrySectionCollapsibleTitleProps {
|
||||
title: string,
|
||||
color: string,
|
||||
isExpanded: boolean,
|
||||
}
|
||||
|
||||
const HAREntrySectionCollapsibleTitle: React.FC<HAREntrySectionCollapsibleTitleProps> = ({title, color, isExpanded}) => {
|
||||
const EntrySectionCollapsibleTitle: React.FC<EntrySectionCollapsibleTitleProps> = ({title, color, isExpanded}) => {
|
||||
return <div className={styles.title}>
|
||||
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`} style={{backgroundColor: color}}>
|
||||
{isExpanded ? '-' : '+'}
|
||||
@ -42,31 +42,31 @@ const HAREntrySectionCollapsibleTitle: React.FC<HAREntrySectionCollapsibleTitleP
|
||||
</div>
|
||||
}
|
||||
|
||||
interface HAREntrySectionContainerProps {
|
||||
interface EntrySectionContainerProps {
|
||||
title: string,
|
||||
color: string,
|
||||
}
|
||||
|
||||
export const HAREntrySectionContainer: React.FC<HAREntrySectionContainerProps> = ({title, color, children}) => {
|
||||
export const EntrySectionContainer: React.FC<EntrySectionContainerProps> = ({title, color, children}) => {
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
return <CollapsibleContainer
|
||||
className={styles.collapsibleContainer}
|
||||
isExpanded={expanded}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
title={<HAREntrySectionCollapsibleTitle title={title} color={color} isExpanded={expanded}/>}
|
||||
title={<EntrySectionCollapsibleTitle title={title} color={color} isExpanded={expanded}/>}
|
||||
>
|
||||
{children}
|
||||
</CollapsibleContainer>
|
||||
}
|
||||
|
||||
interface HAREntryBodySectionProps {
|
||||
interface EntryBodySectionProps {
|
||||
content: any,
|
||||
color: string,
|
||||
encoding?: string,
|
||||
contentType?: string,
|
||||
}
|
||||
|
||||
export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
|
||||
export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
|
||||
color,
|
||||
content,
|
||||
encoding,
|
||||
@ -104,11 +104,11 @@ export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
|
||||
}
|
||||
|
||||
return <React.Fragment>
|
||||
{content && content?.length > 0 && <HAREntrySectionContainer title='Body' color={color}>
|
||||
{content && content?.length > 0 && <EntrySectionContainer title='Body' color={color}>
|
||||
<table>
|
||||
<tbody>
|
||||
<HAREntryViewLine label={'Mime type'} value={contentType}/>
|
||||
<HAREntryViewLine label={'Encoding'} value={encoding}/>
|
||||
<EntryViewLine label={'Mime type'} value={contentType}/>
|
||||
<EntryViewLine label={'Encoding'} value={encoding}/>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -124,35 +124,35 @@ export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
|
||||
code={formatTextBody(content)}
|
||||
language={content?.mimeType ? getLanguage(content.mimeType) : 'default'}
|
||||
/>
|
||||
</HAREntrySectionContainer>}
|
||||
</EntrySectionContainer>}
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
interface HAREntrySectionProps {
|
||||
interface EntrySectionProps {
|
||||
title: string,
|
||||
color: string,
|
||||
arrayToIterate: any[],
|
||||
}
|
||||
|
||||
export const HAREntryTableSection: React.FC<HAREntrySectionProps> = ({title, color, arrayToIterate}) => {
|
||||
export const EntryTableSection: React.FC<EntrySectionProps> = ({title, color, arrayToIterate}) => {
|
||||
return <React.Fragment>
|
||||
{
|
||||
arrayToIterate && arrayToIterate.length > 0 ?
|
||||
<HAREntrySectionContainer title={title} color={color}>
|
||||
<EntrySectionContainer title={title} color={color}>
|
||||
<table>
|
||||
<tbody>
|
||||
{arrayToIterate.map(({name, value}, index) => <HAREntryViewLine key={index} label={name}
|
||||
{arrayToIterate.map(({name, value}, index) => <EntryViewLine key={index} label={name}
|
||||
value={value}/>)}
|
||||
</tbody>
|
||||
</table>
|
||||
</HAREntrySectionContainer> : <span/>
|
||||
</EntrySectionContainer> : <span/>
|
||||
}
|
||||
</React.Fragment>
|
||||
}
|
||||
|
||||
|
||||
|
||||
interface HAREntryPolicySectionProps {
|
||||
interface EntryPolicySectionProps {
|
||||
service: string,
|
||||
title: string,
|
||||
color: string,
|
||||
@ -162,13 +162,13 @@ interface HAREntryPolicySectionProps {
|
||||
}
|
||||
|
||||
|
||||
interface HAREntryPolicySectionCollapsibleTitleProps {
|
||||
interface EntryPolicySectionCollapsibleTitleProps {
|
||||
label: string;
|
||||
matched: string;
|
||||
isExpanded: boolean;
|
||||
}
|
||||
|
||||
const HAREntryPolicySectionCollapsibleTitle: React.FC<HAREntryPolicySectionCollapsibleTitleProps> = ({label, matched, isExpanded}) => {
|
||||
const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsibleTitleProps> = ({label, matched, isExpanded}) => {
|
||||
return <div className={styles.title}>
|
||||
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`}>
|
||||
{isExpanded ? '-' : '+'}
|
||||
@ -182,36 +182,36 @@ const HAREntryPolicySectionCollapsibleTitle: React.FC<HAREntryPolicySectionColla
|
||||
</div>
|
||||
}
|
||||
|
||||
interface HAREntryPolicySectionContainerProps {
|
||||
interface EntryPolicySectionContainerProps {
|
||||
label: string;
|
||||
matched: string;
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export const HAREntryPolicySectionContainer: React.FC<HAREntryPolicySectionContainerProps> = ({label, matched, children}) => {
|
||||
export const EntryPolicySectionContainer: React.FC<EntryPolicySectionContainerProps> = ({label, matched, children}) => {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
return <CollapsibleContainer
|
||||
className={styles.collapsibleContainer}
|
||||
isExpanded={expanded}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
title={<HAREntryPolicySectionCollapsibleTitle label={label} matched={matched} isExpanded={expanded}/>}
|
||||
title={<EntryPolicySectionCollapsibleTitle label={label} matched={matched} isExpanded={expanded}/>}
|
||||
>
|
||||
{children}
|
||||
</CollapsibleContainer>
|
||||
}
|
||||
|
||||
export const HAREntryTablePolicySection: React.FC<HAREntryPolicySectionProps> = ({service, title, color, response, latency, arrayToIterate}) => {
|
||||
export const EntryTablePolicySection: React.FC<EntryPolicySectionProps> = ({service, title, color, response, latency, arrayToIterate}) => {
|
||||
// const base64ToJson = response.content.mimeType === "application/json; charset=utf-8" ? JSON.parse(Buffer.from(response.content.text, "base64").toString()) : {};
|
||||
return <React.Fragment>
|
||||
{
|
||||
arrayToIterate && arrayToIterate.length > 0 ?
|
||||
<>
|
||||
<HAREntrySectionContainer title={title} color={color}>
|
||||
<EntrySectionContainer title={title} color={color}>
|
||||
<table>
|
||||
<tbody>
|
||||
{arrayToIterate.map(({rule, matched}, index) => {
|
||||
return (
|
||||
<HAREntryPolicySectionContainer key={index} label={rule.Name} matched={matched && (rule.Type === 'latency' ? rule.Latency >= latency : true)? "Success" : "Failure"}>
|
||||
<EntryPolicySectionContainer key={index} label={rule.Name} matched={matched && (rule.Type === 'latency' ? rule.Latency >= latency : true)? "Success" : "Failure"}>
|
||||
{
|
||||
<>
|
||||
{
|
||||
@ -251,14 +251,14 @@ export const HAREntryTablePolicySection: React.FC<HAREntryPolicySectionProps> =
|
||||
}
|
||||
</>
|
||||
}
|
||||
</HAREntryPolicySectionContainer>
|
||||
</EntryPolicySectionContainer>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</HAREntrySectionContainer>
|
||||
</EntrySectionContainer>
|
||||
</> : <span/>
|
||||
}
|
||||
</React.Fragment>
|
@ -1,6 +1,6 @@
|
||||
@import "../style/variables.module"
|
||||
@import "../../variables.module"
|
||||
|
||||
.harEntry
|
||||
.Entry
|
||||
font-family: "Source Sans Pro", Lucida Grande, Tahoma, sans-serif
|
||||
height: 100%
|
||||
width: 100%
|
||||
@ -57,4 +57,4 @@
|
||||
text-decoration: none
|
||||
margin-bottom: .5rem
|
||||
overflow-wrap: anywhere
|
||||
padding: 5px 0
|
||||
padding: 5px 0
|
@ -1,7 +1,7 @@
|
||||
import React, {useState} from 'react';
|
||||
import styles from './HAREntryViewer.module.sass';
|
||||
import Tabs from "../Tabs";
|
||||
import {HAREntryTableSection, HAREntryBodySection, HAREntryTablePolicySection} from "./HAREntrySections";
|
||||
import styles from './EntryViewer.module.sass';
|
||||
import Tabs from "../UI/Tabs";
|
||||
import {EntryTableSection, EntryBodySection, EntryTablePolicySection} from "./EntrySections";
|
||||
|
||||
const SectionsRepresentation: React.FC<any> = ({data, color}) => {
|
||||
const sections = []
|
||||
@ -11,12 +11,12 @@ const SectionsRepresentation: React.FC<any> = ({data, color}) => {
|
||||
switch (row.type) {
|
||||
case "table":
|
||||
sections.push(
|
||||
<HAREntryTableSection key={i} title={row.title} color={color} arrayToIterate={JSON.parse(row.data)}/>
|
||||
<EntryTableSection key={i} title={row.title} color={color} arrayToIterate={JSON.parse(row.data)}/>
|
||||
)
|
||||
break;
|
||||
case "body":
|
||||
sections.push(
|
||||
<HAREntryBodySection key={i} color={color} content={row.data} encoding={row.encoding} contentType={row.mime_type}/>
|
||||
<EntryBodySection key={i} color={color} content={row.data} encoding={row.encoding} contentType={row.mime_type}/>
|
||||
)
|
||||
break;
|
||||
default:
|
||||
@ -49,7 +49,7 @@ const AutoRepresentation: React.FC<any> = ({representation, color, isResponseMoc
|
||||
|
||||
const {request, response} = JSON.parse(representation);
|
||||
|
||||
return <div className={styles.harEntry}>
|
||||
return <div className={styles.Entry}>
|
||||
{<div className={styles.body}>
|
||||
<div className={styles.bodyHeader}>
|
||||
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned/>
|
||||
@ -63,7 +63,7 @@ const AutoRepresentation: React.FC<any> = ({representation, color, isResponseMoc
|
||||
</React.Fragment>}
|
||||
{currentTab === TABS[2].tab && <React.Fragment>
|
||||
{// FIXME: Fix here
|
||||
<HAREntryTablePolicySection service={representation.log.entries[0].service} title={'Rule'} color={color} latency={0} response={response} arrayToIterate={rulesMatched ? rulesMatched : []}/>}
|
||||
<EntryTablePolicySection service={representation.log.entries[0].service} title={'Rule'} color={color} latency={0} response={response} arrayToIterate={rulesMatched ? rulesMatched : []}/>}
|
||||
</React.Fragment>}
|
||||
</div>}
|
||||
</div>;
|
||||
@ -76,8 +76,8 @@ interface Props {
|
||||
showTitle?: boolean;
|
||||
}
|
||||
|
||||
const HAREntryViewer: React.FC<Props> = ({representation, color, isResponseMocked, showTitle=true}) => {
|
||||
const EntryViewer: React.FC<Props> = ({representation, color, isResponseMocked, showTitle=true}) => {
|
||||
return <AutoRepresentation representation={representation} color={color} isResponseMocked={isResponseMocked} showTitle={showTitle}/>
|
||||
};
|
||||
|
||||
export default HAREntryViewer;
|
||||
export default EntryViewer;
|
@ -1,4 +1,4 @@
|
||||
@import 'variables.module'
|
||||
@import '../../variables.module'
|
||||
|
||||
.row
|
||||
display: flex
|
@ -1,16 +1,16 @@
|
||||
import React from "react";
|
||||
import styles from './style/HarEntry.module.sass';
|
||||
import StatusCode, {getClassification, StatusCodeClassification} from "./StatusCode";
|
||||
import Protocol, {ProtocolInterface} from "./Protocol"
|
||||
import {EndpointPath} from "./EndpointPath";
|
||||
import ingoingIconSuccess from "./assets/ingoing-traffic-success.svg"
|
||||
import ingoingIconFailure from "./assets/ingoing-traffic-failure.svg"
|
||||
import ingoingIconNeutral from "./assets/ingoing-traffic-neutral.svg"
|
||||
import outgoingIconSuccess from "./assets/outgoing-traffic-success.svg"
|
||||
import outgoingIconFailure from "./assets/outgoing-traffic-failure.svg"
|
||||
import outgoingIconNeutral from "./assets/outgoing-traffic-neutral.svg"
|
||||
import styles from './EntryListItem.module.sass';
|
||||
import StatusCode, {getClassification, StatusCodeClassification} from "../UI/StatusCode";
|
||||
import Protocol, {ProtocolInterface} from "../UI/Protocol"
|
||||
import {EndpointPath} from "../UI/EndpointPath";
|
||||
import ingoingIconSuccess from "../assets/ingoing-traffic-success.svg"
|
||||
import ingoingIconFailure from "../assets/ingoing-traffic-failure.svg"
|
||||
import ingoingIconNeutral from "../assets/ingoing-traffic-neutral.svg"
|
||||
import outgoingIconSuccess from "../assets/outgoing-traffic-success.svg"
|
||||
import outgoingIconFailure from "../assets/outgoing-traffic-failure.svg"
|
||||
import outgoingIconNeutral from "../assets/outgoing-traffic-neutral.svg"
|
||||
|
||||
interface HAREntry {
|
||||
interface Entry {
|
||||
protocol: ProtocolInterface,
|
||||
method?: string,
|
||||
summary: string,
|
||||
@ -34,13 +34,13 @@ interface Rules {
|
||||
numberOfRules: number;
|
||||
}
|
||||
|
||||
interface HAREntryProps {
|
||||
entry: HAREntry;
|
||||
interface EntryProps {
|
||||
entry: Entry;
|
||||
setFocusedEntryId: (id: string) => void;
|
||||
isSelected?: boolean;
|
||||
}
|
||||
|
||||
export const HarEntry: React.FC<HAREntryProps> = ({entry, setFocusedEntryId, isSelected}) => {
|
||||
export const EntryItem: React.FC<EntryProps> = ({entry, setFocusedEntryId, isSelected}) => {
|
||||
const classification = getClassification(entry.status_code)
|
||||
let ingoingIcon;
|
||||
let outgoingIcon;
|
@ -1,10 +1,10 @@
|
||||
import React from "react";
|
||||
import styles from './style/HarFilters.module.sass';
|
||||
import {HARFilterSelect} from "./HARFilterSelect";
|
||||
import styles from './style/Filters.module.sass';
|
||||
import {FilterSelect} from "./UI/FilterSelect";
|
||||
import {TextField} from "@material-ui/core";
|
||||
import {ALL_KEY} from "./Select";
|
||||
import {ALL_KEY} from "./UI/Select";
|
||||
|
||||
interface HarFiltersProps {
|
||||
interface FiltersProps {
|
||||
methodsFilter: Array<string>;
|
||||
setMethodsFilter: (methods: Array<string>) => void;
|
||||
statusFilter: Array<string>;
|
||||
@ -13,7 +13,7 @@ interface HarFiltersProps {
|
||||
setPathFilter: (val: string) => void;
|
||||
}
|
||||
|
||||
export const HarFilters: React.FC<HarFiltersProps> = ({methodsFilter, setMethodsFilter, statusFilter, setStatusFilter, pathFilter, setPathFilter}) => {
|
||||
export const Filters: React.FC<FiltersProps> = ({methodsFilter, setMethodsFilter, statusFilter, setStatusFilter, pathFilter, setPathFilter}) => {
|
||||
|
||||
return <div className={styles.container}>
|
||||
<MethodFilter methodsFilter={methodsFilter} setMethodsFilter={setMethodsFilter}/>
|
||||
@ -59,7 +59,7 @@ const MethodFilter: React.FC<MethodFilterProps> = ({methodsFilter, setMethodsFil
|
||||
}
|
||||
|
||||
return <FilterContainer>
|
||||
<HARFilterSelect
|
||||
<FilterSelect
|
||||
items={Object.values(HTTPMethod)}
|
||||
allowMultiple={true}
|
||||
value={methodsFilter}
|
||||
@ -91,7 +91,7 @@ const StatusTypesFilter: React.FC<StatusTypesFilterProps> = ({statusFilter, setS
|
||||
}
|
||||
|
||||
return <FilterContainer>
|
||||
<HARFilterSelect
|
||||
<FilterSelect
|
||||
items={Object.values(StatusType)}
|
||||
allowMultiple={true}
|
||||
value={statusFilter}
|
@ -1,27 +0,0 @@
|
||||
import prevIcon from "./assets/icon-prev.svg";
|
||||
import nextIcon from "./assets/icon-next.svg";
|
||||
import {Box} from "@material-ui/core";
|
||||
import React from "react";
|
||||
import styles from './style/HarPaging.module.sass'
|
||||
import numeral from 'numeral';
|
||||
|
||||
interface HarPagingProps {
|
||||
showPageNumber?: boolean;
|
||||
}
|
||||
|
||||
export const HarPaging: React.FC<HarPagingProps> = ({showPageNumber=false}) => {
|
||||
|
||||
return <Box className={styles.HarPaging} display='flex'>
|
||||
<img src={prevIcon} onClick={() => {
|
||||
// harStore.data.moveBack(); todo
|
||||
}} alt="back"/>
|
||||
{showPageNumber && <span className={styles.text}>
|
||||
Page <span className={styles.pageNumber}>
|
||||
{/*{numeral(harStore.data.currentPage).format(0, 0)}*/} //todo
|
||||
</span>
|
||||
</span>}
|
||||
<img src={nextIcon} onClick={() => {
|
||||
// harStore.data.moveNext(); todo
|
||||
}} alt="next"/>
|
||||
</Box>
|
||||
};
|
@ -1,14 +1,14 @@
|
||||
import React, {useEffect, useRef, useState} from "react";
|
||||
import {HarFilters} from "./HarFilters";
|
||||
import {HarEntriesList} from "./HarEntriesList";
|
||||
import {Filters} from "./Filters";
|
||||
import {EntriesList} from "./EntriesList";
|
||||
import {makeStyles} from "@material-ui/core";
|
||||
import "./style/HarPage.sass";
|
||||
import styles from './style/HarEntriesList.module.sass';
|
||||
import {HAREntryDetailed} from "./HarEntryDetailed";
|
||||
import "./style/TrafficPage.sass";
|
||||
import styles from './style/EntriesList.module.sass';
|
||||
import {EntryDetailed} from "./EntryDetailed";
|
||||
import playIcon from './assets/run.svg';
|
||||
import pauseIcon from './assets/pause.svg';
|
||||
import variables from './style/variables.module.scss';
|
||||
import {StatusBar} from "./StatusBar";
|
||||
import variables from '../variables.module.scss';
|
||||
import {StatusBar} from "./UI/StatusBar";
|
||||
import Api, {MizuWebsocketURL} from "../helpers/api";
|
||||
|
||||
const useLayoutStyles = makeStyles(() => ({
|
||||
@ -21,7 +21,7 @@ const useLayoutStyles = makeStyles(() => ({
|
||||
background: variables.headerBackgoundColor
|
||||
},
|
||||
|
||||
harViewer: {
|
||||
viewer: {
|
||||
display: 'flex',
|
||||
overflowY: 'auto',
|
||||
height: "calc(100% - 70px)",
|
||||
@ -36,20 +36,20 @@ enum ConnectionStatus {
|
||||
Paused
|
||||
}
|
||||
|
||||
interface HarPageProps {
|
||||
interface TrafficPageProps {
|
||||
setAnalyzeStatus: (status: any) => void;
|
||||
onTLSDetected: (destAddress: string) => void;
|
||||
}
|
||||
|
||||
const api = new Api();
|
||||
|
||||
export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected}) => {
|
||||
export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLSDetected}) => {
|
||||
|
||||
const classes = useLayoutStyles();
|
||||
|
||||
const [entries, setEntries] = useState([] as any);
|
||||
const [focusedEntryId, setFocusedEntryId] = useState(null);
|
||||
const [selectedHarEntry, setSelectedHarEntry] = useState(null);
|
||||
const [selectedEntryData, setSelectedEntryData] = useState(null);
|
||||
const [connection, setConnection] = useState(ConnectionStatus.Closed);
|
||||
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
|
||||
const [noMoreDataBottom, setNoMoreDataBottom] = useState(false);
|
||||
@ -129,11 +129,11 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
||||
|
||||
useEffect(() => {
|
||||
if (!focusedEntryId) return;
|
||||
setSelectedHarEntry(null);
|
||||
setSelectedEntryData(null);
|
||||
(async () => {
|
||||
try {
|
||||
const entryData = await api.getEntry(focusedEntryId);
|
||||
setSelectedHarEntry(entryData);
|
||||
setSelectedEntryData(entryData);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@ -170,16 +170,16 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
||||
const onScrollEvent = (isAtBottom) => {
|
||||
isAtBottom ? setDisableScrollList(false) : setDisableScrollList(true)
|
||||
}
|
||||
|
||||
|
||||
const isScrollable = (element) => {
|
||||
return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
|
||||
return element.scrollHeight > element.clientHeight;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="HarPage">
|
||||
<div className="harPageHeader">
|
||||
<div className="TrafficPage">
|
||||
<div className="TrafficPageHeader">
|
||||
<img style={{cursor: "pointer", marginRight: 15, height: 30}} alt="pause"
|
||||
src={connection === ConnectionStatus.Connected ? pauseIcon : playIcon} onClick={toggleConnection}/>
|
||||
src={connection === ConnectionStatus.Connected ? pauseIcon : playIcon} onClick={toggleConnection}/>
|
||||
<div className="connectionText">
|
||||
{getConnectionTitle()}
|
||||
<div className={"indicatorContainer " + getConnectionStatusClass(true)}>
|
||||
@ -187,9 +187,9 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{entries.length > 0 && <div className="HarPage-Container">
|
||||
<div className="HarPage-ListContainer">
|
||||
<HarFilters methodsFilter={methodsFilter}
|
||||
{entries.length > 0 && <div className="TrafficPage-Container">
|
||||
<div className="TrafficPage-ListContainer">
|
||||
<Filters methodsFilter={methodsFilter}
|
||||
setMethodsFilter={setMethodsFilter}
|
||||
statusFilter={statusFilter}
|
||||
setStatusFilter={setStatusFilter}
|
||||
@ -197,7 +197,7 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
||||
setPathFilter={setPathFilter}
|
||||
/>
|
||||
<div className={styles.container}>
|
||||
<HarEntriesList entries={entries}
|
||||
<EntriesList entries={entries}
|
||||
setEntries={setEntries}
|
||||
focusedEntryId={focusedEntryId}
|
||||
setFocusedEntryId={setFocusedEntryId}
|
||||
@ -216,8 +216,7 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.details}>
|
||||
{selectedHarEntry &&
|
||||
<HAREntryDetailed harEntry={selectedHarEntry} classes={{root: classes.harViewer}}/>}
|
||||
{selectedEntryData && <EntryDetailed entryData={selectedEntryData}/>}
|
||||
</div>
|
||||
</div>}
|
||||
{tappingStatus?.pods != null && <StatusBar tappingStatus={tappingStatus}/>}
|
@ -1,6 +1,6 @@
|
||||
import React, {useState} from "react";
|
||||
import collapsedImg from "./assets/collapsed.svg";
|
||||
import expandedImg from "./assets/expanded.svg";
|
||||
import collapsedImg from "../assets/collapsed.svg";
|
||||
import expandedImg from "../assets/expanded.svg";
|
||||
import "./style/CollapsibleContainer.sass";
|
||||
|
||||
interface Props {
|
@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||
import duplicateImg from "./assets/duplicate.svg";
|
||||
import duplicateImg from "../assets/duplicate.svg";
|
||||
import './style/FancyTextDisplay.sass';
|
||||
|
||||
interface Props {
|
@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import { MenuItem } from '@material-ui/core';
|
||||
import style from './style/HARFilterSelect.module.sass';
|
||||
import style from './style/FilterSelect.module.sass';
|
||||
import { Select, SelectProps } from "./Select";
|
||||
|
||||
interface HARFilterSelectProps extends SelectProps {
|
||||
interface FilterSelectProps extends SelectProps {
|
||||
items: string[];
|
||||
value: string | string[];
|
||||
onChange: (string) => void;
|
||||
@ -12,7 +12,7 @@ interface HARFilterSelectProps extends SelectProps {
|
||||
transformDisplay?: (string) => string;
|
||||
}
|
||||
|
||||
export const HARFilterSelect: React.FC<HARFilterSelectProps> = ({items, value, onChange, label, allowMultiple= false, transformDisplay}) => {
|
||||
export const FilterSelect: React.FC<FilterSelectProps> = ({items, value, onChange, label, allowMultiple= false, transformDisplay}) => {
|
||||
return <Select
|
||||
value={value}
|
||||
multiple={allowMultiple}
|
||||
@ -20,7 +20,7 @@ export const HARFilterSelect: React.FC<HARFilterSelectProps> = ({items, value, o
|
||||
onChange={onChange}
|
||||
transformDisplay={transformDisplay}
|
||||
labelOnTop={true}
|
||||
labelClassName={style.HARSelectLabel}
|
||||
labelClassName={style.SelectLabel}
|
||||
trimItemsWhenMultiple={true}
|
||||
>
|
||||
{items?.map(item => <MenuItem key={item} value={item}><span className='uppercase'>{item}</span></MenuItem>)}
|
@ -1,4 +1,4 @@
|
||||
import {ReactComponent as DefaultIconDown} from './assets/default_icon_down.svg';
|
||||
import {ReactComponent as DefaultIconDown} from '../assets/default_icon_down.svg';
|
||||
import {MenuItem, Select as MUISelect} from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import {SelectProps as MUISelectProps} from '@material-ui/core/Select/Select';
|
@ -7,11 +7,11 @@ export enum StatusCodeClassification {
|
||||
NEUTRAL = "neutral"
|
||||
}
|
||||
|
||||
interface HAREntryProps {
|
||||
interface EntryProps {
|
||||
statusCode: number
|
||||
}
|
||||
|
||||
const StatusCode: React.FC<HAREntryProps> = ({statusCode}) => {
|
||||
const StatusCode: React.FC<EntryProps> = ({statusCode}) => {
|
||||
|
||||
const classification = getClassification(statusCode)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Tooltip from "./Tooltip";
|
||||
import React from "react";
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
import variables from './style/variables.module.scss';
|
||||
import variables from '../../variables.module.scss';
|
||||
|
||||
interface Tab {
|
||||
tab: string,
|
3
ui/src/components/UI/style/FilterSelect.module.sass
Normal file
3
ui/src/components/UI/style/FilterSelect.module.sass
Normal file
@ -0,0 +1,3 @@
|
||||
.SelectLabel
|
||||
color: #8f9bb2
|
||||
font-size: 11px
|
@ -1,5 +1,3 @@
|
||||
@import 'variables.module'
|
||||
|
||||
.base
|
||||
display: inline-block
|
||||
text-align: center
|
@ -1,4 +1,4 @@
|
||||
@import 'variables.module.scss'
|
||||
@import '../../../variables.module'
|
||||
|
||||
.statusBar
|
||||
position: absolute
|
||||
@ -32,4 +32,4 @@
|
||||
|
||||
.expandedStatusBar
|
||||
max-height: 100vh
|
||||
padding-bottom: 15px
|
||||
padding-bottom: 15px
|
@ -1,4 +1,4 @@
|
||||
@import 'variables.module'
|
||||
@import '../../../variables.module'
|
||||
|
||||
.base
|
||||
border-radius: 4px
|
@ -1,4 +1,4 @@
|
||||
@import 'variables.module'
|
||||
@import '../../../variables.module'
|
||||
|
||||
.protocol
|
||||
border-radius: 4px
|
||||
@ -24,4 +24,4 @@
|
||||
-khtml-user-select: none
|
||||
-moz-user-select: none
|
||||
-ms-user-select: none
|
||||
user-select: none
|
||||
user-select: none
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 301 B |
@ -1,4 +1,4 @@
|
||||
@import "variables.module"
|
||||
@import "../../variables.module"
|
||||
|
||||
.list
|
||||
overflow: scroll
|
@ -1,4 +1,4 @@
|
||||
@import "variables.module"
|
||||
@import "../../variables.module"
|
||||
|
||||
.container
|
||||
display: flex
|
@ -1,3 +0,0 @@
|
||||
.HARSelectLabel
|
||||
color: #8f9bb2
|
||||
font-size: 11px
|
@ -1,7 +0,0 @@
|
||||
.loader
|
||||
margin: 30px auto 0
|
||||
|
||||
.har
|
||||
display: flex
|
||||
overflow: scroll
|
||||
height: calc(100% - 1.75rem)
|
@ -1,16 +0,0 @@
|
||||
.HarPaging
|
||||
justify-content: center
|
||||
align-items: center
|
||||
padding-bottom: 10px
|
||||
|
||||
img
|
||||
cursor: pointer
|
||||
|
||||
.text
|
||||
color: #8f9bb2
|
||||
font-size: 14px
|
||||
padding: 0 10px
|
||||
|
||||
.pageNumber
|
||||
color: #fff
|
||||
font-weight: 600
|
@ -1,6 +1,6 @@
|
||||
@import 'variables.module.scss'
|
||||
@import '../../variables.module.scss'
|
||||
|
||||
.HarPage
|
||||
.TrafficPage
|
||||
width: 100%
|
||||
display: flex
|
||||
flex-direction: column
|
||||
@ -8,34 +8,34 @@
|
||||
flex-grow: 1
|
||||
height: calc(100vh - 70px)
|
||||
|
||||
.harPageHeader
|
||||
.TrafficPageHeader
|
||||
padding: 20px 24px
|
||||
display: flex
|
||||
align-items: center
|
||||
background-color: $header-background-color
|
||||
|
||||
.HarPage-Header
|
||||
.TrafficPage-Header
|
||||
display: flex
|
||||
height: 2.5%
|
||||
justify-content: space-between
|
||||
align-items: center
|
||||
padding: 18px 15px
|
||||
|
||||
.HarPage-Header-Image
|
||||
.TrafficPage-Header-Image
|
||||
width: 22px
|
||||
height: 22px
|
||||
|
||||
.HarPage-Header-Text
|
||||
.TrafficPage-Header-Text
|
||||
margin-left: 10px
|
||||
font-family: 'Source Sans Pro', serif
|
||||
font-size: 14px
|
||||
font-weight: bold
|
||||
color: #f7f9fc
|
||||
|
||||
.HarPage-Header-Actions
|
||||
.TrafficPage-Header-Actions
|
||||
margin-left: auto
|
||||
|
||||
.HarPage-Header-Actions-Image
|
||||
.TrafficPage-Header-Actions-Image
|
||||
width: 22px
|
||||
height: 22px
|
||||
cursor: pointer
|
||||
@ -43,7 +43,7 @@
|
||||
margin-left: auto
|
||||
transform: translate(0 ,25%)
|
||||
|
||||
.HarPage-Viewer
|
||||
.TrafficPage-Viewer
|
||||
height: 96.5%
|
||||
overflow: auto
|
||||
|
||||
@ -53,25 +53,25 @@
|
||||
display: block
|
||||
overflow-y: auto
|
||||
|
||||
.harContent
|
||||
.TrafficContent
|
||||
box-sizing: border-box
|
||||
height: calc(100% - 60px)
|
||||
overflow: scroll
|
||||
|
||||
.HarPage-Container
|
||||
.TrafficPage-Container
|
||||
display: flex
|
||||
flex-grow: 1
|
||||
overflow: hidden
|
||||
background-color: $data-background-color
|
||||
|
||||
.HarPage-ListContainer
|
||||
.TrafficPage-ListContainer
|
||||
display: flex
|
||||
flex-grow: 1
|
||||
overflow: hidden
|
||||
padding-left: 24px
|
||||
flex-direction: column
|
||||
|
||||
.HarPage-DetailContainer
|
||||
.TrafficPage-DetailContainer
|
||||
width: 45vw
|
||||
background-color: #171c30
|
||||
flex: 0 0 50%
|
@ -1,35 +0,0 @@
|
||||
export const singleEntryToHAR = (entry) => {
|
||||
|
||||
if (!entry) return null;
|
||||
|
||||
const modifiedEntry = {
|
||||
...entry,
|
||||
"startedDateTime": "2019-10-08T11:49:51.090+03:00",
|
||||
"cache": {},
|
||||
"timings": {
|
||||
"blocked": -1,
|
||||
"dns": -1,
|
||||
"connect": -1,
|
||||
"ssl": -1,
|
||||
"send": -1,
|
||||
"wait": -1,
|
||||
"receive": -1
|
||||
},
|
||||
"time": -1
|
||||
};
|
||||
|
||||
const har = {
|
||||
log: {
|
||||
entries: [modifiedEntry],
|
||||
version: "1.2",
|
||||
creator: {
|
||||
"name": "Firefox",
|
||||
"version": "69.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return har;
|
||||
};
|
||||
|
||||
export const formatSize = (n: number) => n > 1000 ? `${Math.round(n / 1000)}KB` : `${n} B`;
|
@ -1,10 +0,0 @@
|
||||
import {useState} from "react";
|
||||
|
||||
export default function useToggle(initialState: boolean = false): [boolean, () => void] {
|
||||
|
||||
const [isToggled, setToggled] = useState(initialState);
|
||||
|
||||
return [isToggled, () => {
|
||||
setToggled(!isToggled)
|
||||
}];
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
@import 'src/components/style/variables.module'
|
||||
@import './variables.module'
|
||||
|
||||
html,
|
||||
body
|
||||
|
Loading…
Reference in New Issue
Block a user