mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-08-13 14:17:54 +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.
|
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 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 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 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 extensions []*tapApi.Extension // global
|
||||||
var extensionsMap map[string]*tapApi.Extension // global
|
var extensionsMap map[string]*tapApi.Extension // global
|
||||||
@ -43,8 +45,8 @@ func main() {
|
|||||||
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
||||||
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
||||||
|
|
||||||
if !*tapperMode && !*apiServerMode && !*standaloneMode {
|
if !*tapperMode && !*apiServerMode && !*standaloneMode && !*harsReaderMode {
|
||||||
panic("One of the flags --tap, --api or --standalone must be provided")
|
panic("One of the flags --tap, --api or --standalone or --hars-read must be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *standaloneMode {
|
if *standaloneMode {
|
||||||
@ -90,6 +92,13 @@ func main() {
|
|||||||
go api.StartReadingEntries(socketHarOutChannel, nil, extensionsMap)
|
go api.StartReadingEntries(socketHarOutChannel, nil, extensionsMap)
|
||||||
|
|
||||||
hostApi(socketHarOutChannel)
|
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)
|
signalChan := make(chan os.Signal, 1)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
@import 'components/style/variables.module'
|
@import './variables.module'
|
||||||
|
|
||||||
.mizuApp
|
.mizuApp
|
||||||
background-color: $main-background-color
|
background-color: $main-background-color
|
||||||
|
@ -2,8 +2,8 @@ import React, {useEffect, useState} from 'react';
|
|||||||
import './App.sass';
|
import './App.sass';
|
||||||
import logo from './components/assets/Mizu-logo.svg';
|
import logo from './components/assets/Mizu-logo.svg';
|
||||||
import {Button, Snackbar} from "@material-ui/core";
|
import {Button, Snackbar} from "@material-ui/core";
|
||||||
import {HarPage} from "./components/HarPage";
|
import {TrafficPage} from "./components/TrafficPage";
|
||||||
import Tooltip from "./components/Tooltip";
|
import Tooltip from "./components/UI/Tooltip";
|
||||||
import {makeStyles} from "@material-ui/core/styles";
|
import {makeStyles} from "@material-ui/core/styles";
|
||||||
import MuiAlert from '@material-ui/lab/Alert';
|
import MuiAlert from '@material-ui/lab/Alert';
|
||||||
import Api from "./helpers/api";
|
import Api from "./helpers/api";
|
||||||
@ -116,7 +116,7 @@ const App = () => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<HarPage setAnalyzeStatus={setAnalyzeStatus} onTLSDetected={onTLSDetected}/>
|
<TrafficPage setAnalyzeStatus={setAnalyzeStatus} onTLSDetected={onTLSDetected}/>
|
||||||
<Snackbar open={showTLSWarning && !userDismissedTLSWarning}>
|
<Snackbar open={showTLSWarning && !userDismissedTLSWarning}>
|
||||||
<MuiAlert elevation={6} variant="filled" onClose={() => setUserDismissedTLSWarning(true)} severity="warning">
|
<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.
|
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 {EntryItem} from "./EntryListItem/EntryListItem";
|
||||||
import React, {useCallback, useEffect, useMemo, useState} from "react";
|
import React, {useCallback, useEffect, useMemo, useRef, useState} from "react";
|
||||||
import styles from './style/HarEntriesList.module.sass';
|
import styles from './style/EntriesList.module.sass';
|
||||||
import spinner from './assets/spinner.svg';
|
import spinner from './assets/spinner.svg';
|
||||||
import ScrollableFeed from "react-scrollable-feed";
|
import ScrollableFeed from "react-scrollable-feed";
|
||||||
import {StatusType} from "./HarFilters";
|
import {StatusType} from "./Filters";
|
||||||
import Api from "../helpers/api";
|
import Api from "../helpers/api";
|
||||||
import uninon from "./assets/union.svg";
|
import down from "./assets/downImg.svg";
|
||||||
|
|
||||||
interface HarEntriesListProps {
|
interface EntriesListProps {
|
||||||
entries: any[];
|
entries: any[];
|
||||||
setEntries: (entries: any[]) => void;
|
setEntries: (entries: any[]) => void;
|
||||||
focusedEntryId: string;
|
focusedEntryId: string;
|
||||||
@ -32,11 +32,13 @@ enum FetchOperator {
|
|||||||
|
|
||||||
const api = new Api();
|
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 [loadMoreTop, setLoadMoreTop] = useState(false);
|
||||||
const [isLoadingTop, setIsLoadingTop] = useState(false);
|
const [isLoadingTop, setIsLoadingTop] = useState(false);
|
||||||
|
|
||||||
|
const scrollableRef = useRef(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const list = document.getElementById('list').firstElementChild;
|
const list = document.getElementById('list').firstElementChild;
|
||||||
list.addEventListener('scroll', (e) => {
|
list.addEventListener('scroll', (e) => {
|
||||||
@ -114,24 +116,20 @@ export const HarEntriesList: React.FC<HarEntriesListProps> = ({entries, setEntri
|
|||||||
{isLoadingTop && <div className={styles.spinnerContainer}>
|
{isLoadingTop && <div className={styles.spinnerContainer}>
|
||||||
<img alt="spinner" src={spinner} style={{height: 25}}/>
|
<img alt="spinner" src={spinner} style={{height: 25}}/>
|
||||||
</div>}
|
</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>}
|
{noMoreDataTop && !connectionOpen && <div id="noMoreDataTop" className={styles.noMoreDataAvailable}>No more data available</div>}
|
||||||
{filteredEntries.map(entry => <HarEntry key={entry.id}
|
{filteredEntries.map(entry => <EntryItem key={entry.id}
|
||||||
entry={entry}
|
entry={entry}
|
||||||
setFocusedEntryId={setFocusedEntryId}
|
setFocusedEntryId={setFocusedEntryId}
|
||||||
isSelected={focusedEntryId === entry.id}/>)}
|
isSelected={focusedEntryId === entry.id}/>)}
|
||||||
{!connectionOpen && !noMoreDataBottom && <div className={styles.fetchButtonContainer}>
|
{!connectionOpen && !noMoreDataBottom && <div className={styles.fetchButtonContainer}>
|
||||||
<div className={styles.styledButton} onClick={() => getNewEntries()}>Fetch more entries</div>
|
<div className={styles.styledButton} onClick={() => getNewEntries()}>Fetch more entries</div>
|
||||||
</div>}
|
</div>}
|
||||||
</ScrollableFeed>
|
</ScrollableFeed>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
className={`${styles.btnLive} ${scrollableList ? styles.showButton : styles.hideButton}`}
|
className={`${styles.btnLive} ${scrollableList ? styles.showButton : styles.hideButton}`}
|
||||||
onClick={(_) => {
|
onClick={(_) => scrollableRef.current.scrollToBottom()}>
|
||||||
const list = listEntryREF.current.firstChild;
|
<img alt="down" src={down} />
|
||||||
if(list instanceof HTMLElement) {
|
|
||||||
list.scrollTo({ top: list.scrollHeight, behavior: 'smooth' })
|
|
||||||
}
|
|
||||||
}}><img alt="Union" src={uninon} />
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1,10 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {singleEntryToHAR} from "./utils";
|
import EntryViewer from "./EntryDetailed/EntryViewer";
|
||||||
import HAREntryViewer from "./HarEntryViewer/HAREntryViewer";
|
|
||||||
import {makeStyles} from "@material-ui/core";
|
import {makeStyles} from "@material-ui/core";
|
||||||
import Protocol from "./Protocol"
|
import Protocol from "./UI/Protocol"
|
||||||
import StatusCode from "./StatusCode";
|
import StatusCode from "./UI/StatusCode";
|
||||||
import {EndpointPath} from "./EndpointPath";
|
import {EndpointPath} from "./UI/EndpointPath";
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
entryTitle: {
|
entryTitle: {
|
||||||
@ -27,34 +26,32 @@ const useStyles = makeStyles(() => ({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface HarEntryDetailedProps {
|
interface EntryDetailedProps {
|
||||||
harEntry: any;
|
entryData: any
|
||||||
classes?: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const formatSize = (n: number) => n > 1000 ? `${Math.round(n / 1000)}KB` : `${n} B`;
|
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 classes = useStyles();
|
||||||
|
|
||||||
const {log: {entries}} = har;
|
console.log("data:", data)
|
||||||
const {response} = JSON.parse(entries[0].entry);
|
const {response} = JSON.parse(data.entry);
|
||||||
|
|
||||||
|
|
||||||
return <div className={classes.entryTitle}>
|
return <div className={classes.entryTitle}>
|
||||||
<Protocol protocol={protocol} horizontal={true}/>
|
<Protocol protocol={protocol} horizontal={true}/>
|
||||||
<div style={{right: "30px", position: "absolute", display: "flex"}}>
|
<div style={{right: "30px", position: "absolute", display: "flex"}}>
|
||||||
{response.payload && <div style={{margin: "0 18px", opacity: 0.5}}>{formatSize(response.payload.bodySize)}</div>}
|
{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>
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const HarEntrySummary: React.FC<any> = ({har}) => {
|
const EntrySummary: React.FC<any> = ({data}) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const {log: {entries}} = har;
|
const {response, request} = JSON.parse(data.entry);
|
||||||
const {response, request} = JSON.parse(entries[0].entry);
|
|
||||||
|
|
||||||
return <div className={classes.entrySummary}>
|
return <div className={classes.entrySummary}>
|
||||||
{response?.payload && response.payload?.details && "status" in response.payload.details && <div style={{marginRight: 8}}>
|
{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>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const HAREntryDetailed: React.FC<HarEntryDetailedProps> = ({classes, harEntry}) => {
|
export const EntryDetailed: React.FC<EntryDetailedProps> = ({entryData}) => {
|
||||||
const har = singleEntryToHAR(harEntry.data);
|
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<HarEntryTitle protocol={harEntry.protocol} har={har}/>
|
<EntryTitle protocol={entryData.protocol} data={entryData.data}/>
|
||||||
{har && <HarEntrySummary har={har}/>}
|
{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
|
.title
|
||||||
display: flex
|
display: flex
|
@ -1,17 +1,17 @@
|
|||||||
import styles from "./HAREntrySections.module.sass";
|
import styles from "./EntrySections.module.sass";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {SyntaxHighlighter} from "../SyntaxHighlighter/index";
|
import {SyntaxHighlighter} from "../UI/SyntaxHighlighter/index";
|
||||||
import CollapsibleContainer from "../CollapsibleContainer";
|
import CollapsibleContainer from "../UI/CollapsibleContainer";
|
||||||
import FancyTextDisplay from "../FancyTextDisplay";
|
import FancyTextDisplay from "../UI/FancyTextDisplay";
|
||||||
import Checkbox from "../Checkbox";
|
import Checkbox from "../UI/Checkbox";
|
||||||
import ProtobufDecoder from "protobuf-decoder";
|
import ProtobufDecoder from "protobuf-decoder";
|
||||||
|
|
||||||
interface HAREntryViewLineProps {
|
interface EntryViewLineProps {
|
||||||
label: string;
|
label: string;
|
||||||
value: number | 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}>
|
return (label && value && <tr className={styles.dataLine}>
|
||||||
<td className={styles.dataKey}>{label}</td>
|
<td className={styles.dataKey}>{label}</td>
|
||||||
<td>
|
<td>
|
||||||
@ -27,13 +27,13 @@ const HAREntryViewLine: React.FC<HAREntryViewLineProps> = ({label, value}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface HAREntrySectionCollapsibleTitleProps {
|
interface EntrySectionCollapsibleTitleProps {
|
||||||
title: string,
|
title: string,
|
||||||
color: string,
|
color: string,
|
||||||
isExpanded: boolean,
|
isExpanded: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const HAREntrySectionCollapsibleTitle: React.FC<HAREntrySectionCollapsibleTitleProps> = ({title, color, isExpanded}) => {
|
const EntrySectionCollapsibleTitle: React.FC<EntrySectionCollapsibleTitleProps> = ({title, color, isExpanded}) => {
|
||||||
return <div className={styles.title}>
|
return <div className={styles.title}>
|
||||||
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`} style={{backgroundColor: color}}>
|
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`} style={{backgroundColor: color}}>
|
||||||
{isExpanded ? '-' : '+'}
|
{isExpanded ? '-' : '+'}
|
||||||
@ -42,31 +42,31 @@ const HAREntrySectionCollapsibleTitle: React.FC<HAREntrySectionCollapsibleTitleP
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HAREntrySectionContainerProps {
|
interface EntrySectionContainerProps {
|
||||||
title: string,
|
title: string,
|
||||||
color: 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);
|
const [expanded, setExpanded] = useState(true);
|
||||||
return <CollapsibleContainer
|
return <CollapsibleContainer
|
||||||
className={styles.collapsibleContainer}
|
className={styles.collapsibleContainer}
|
||||||
isExpanded={expanded}
|
isExpanded={expanded}
|
||||||
onClick={() => setExpanded(!expanded)}
|
onClick={() => setExpanded(!expanded)}
|
||||||
title={<HAREntrySectionCollapsibleTitle title={title} color={color} isExpanded={expanded}/>}
|
title={<EntrySectionCollapsibleTitle title={title} color={color} isExpanded={expanded}/>}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</CollapsibleContainer>
|
</CollapsibleContainer>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HAREntryBodySectionProps {
|
interface EntryBodySectionProps {
|
||||||
content: any,
|
content: any,
|
||||||
color: string,
|
color: string,
|
||||||
encoding?: string,
|
encoding?: string,
|
||||||
contentType?: string,
|
contentType?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
|
export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
|
||||||
color,
|
color,
|
||||||
content,
|
content,
|
||||||
encoding,
|
encoding,
|
||||||
@ -104,11 +104,11 @@ export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
{content && content?.length > 0 && <HAREntrySectionContainer title='Body' color={color}>
|
{content && content?.length > 0 && <EntrySectionContainer title='Body' color={color}>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<HAREntryViewLine label={'Mime type'} value={contentType}/>
|
<EntryViewLine label={'Mime type'} value={contentType}/>
|
||||||
<HAREntryViewLine label={'Encoding'} value={encoding}/>
|
<EntryViewLine label={'Encoding'} value={encoding}/>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -124,35 +124,35 @@ export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
|
|||||||
code={formatTextBody(content)}
|
code={formatTextBody(content)}
|
||||||
language={content?.mimeType ? getLanguage(content.mimeType) : 'default'}
|
language={content?.mimeType ? getLanguage(content.mimeType) : 'default'}
|
||||||
/>
|
/>
|
||||||
</HAREntrySectionContainer>}
|
</EntrySectionContainer>}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HAREntrySectionProps {
|
interface EntrySectionProps {
|
||||||
title: string,
|
title: string,
|
||||||
color: string,
|
color: string,
|
||||||
arrayToIterate: any[],
|
arrayToIterate: any[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HAREntryTableSection: React.FC<HAREntrySectionProps> = ({title, color, arrayToIterate}) => {
|
export const EntryTableSection: React.FC<EntrySectionProps> = ({title, color, arrayToIterate}) => {
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
{
|
{
|
||||||
arrayToIterate && arrayToIterate.length > 0 ?
|
arrayToIterate && arrayToIterate.length > 0 ?
|
||||||
<HAREntrySectionContainer title={title} color={color}>
|
<EntrySectionContainer title={title} color={color}>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
{arrayToIterate.map(({name, value}, index) => <HAREntryViewLine key={index} label={name}
|
{arrayToIterate.map(({name, value}, index) => <EntryViewLine key={index} label={name}
|
||||||
value={value}/>)}
|
value={value}/>)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</HAREntrySectionContainer> : <span/>
|
</EntrySectionContainer> : <span/>
|
||||||
}
|
}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface HAREntryPolicySectionProps {
|
interface EntryPolicySectionProps {
|
||||||
service: string,
|
service: string,
|
||||||
title: string,
|
title: string,
|
||||||
color: string,
|
color: string,
|
||||||
@ -162,13 +162,13 @@ interface HAREntryPolicySectionProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface HAREntryPolicySectionCollapsibleTitleProps {
|
interface EntryPolicySectionCollapsibleTitleProps {
|
||||||
label: string;
|
label: string;
|
||||||
matched: string;
|
matched: string;
|
||||||
isExpanded: boolean;
|
isExpanded: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HAREntryPolicySectionCollapsibleTitle: React.FC<HAREntryPolicySectionCollapsibleTitleProps> = ({label, matched, isExpanded}) => {
|
const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsibleTitleProps> = ({label, matched, isExpanded}) => {
|
||||||
return <div className={styles.title}>
|
return <div className={styles.title}>
|
||||||
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`}>
|
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`}>
|
||||||
{isExpanded ? '-' : '+'}
|
{isExpanded ? '-' : '+'}
|
||||||
@ -182,36 +182,36 @@ const HAREntryPolicySectionCollapsibleTitle: React.FC<HAREntryPolicySectionColla
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HAREntryPolicySectionContainerProps {
|
interface EntryPolicySectionContainerProps {
|
||||||
label: string;
|
label: string;
|
||||||
matched: string;
|
matched: string;
|
||||||
children?: any;
|
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);
|
const [expanded, setExpanded] = useState(false);
|
||||||
return <CollapsibleContainer
|
return <CollapsibleContainer
|
||||||
className={styles.collapsibleContainer}
|
className={styles.collapsibleContainer}
|
||||||
isExpanded={expanded}
|
isExpanded={expanded}
|
||||||
onClick={() => setExpanded(!expanded)}
|
onClick={() => setExpanded(!expanded)}
|
||||||
title={<HAREntryPolicySectionCollapsibleTitle label={label} matched={matched} isExpanded={expanded}/>}
|
title={<EntryPolicySectionCollapsibleTitle label={label} matched={matched} isExpanded={expanded}/>}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</CollapsibleContainer>
|
</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()) : {};
|
// const base64ToJson = response.content.mimeType === "application/json; charset=utf-8" ? JSON.parse(Buffer.from(response.content.text, "base64").toString()) : {};
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
{
|
{
|
||||||
arrayToIterate && arrayToIterate.length > 0 ?
|
arrayToIterate && arrayToIterate.length > 0 ?
|
||||||
<>
|
<>
|
||||||
<HAREntrySectionContainer title={title} color={color}>
|
<EntrySectionContainer title={title} color={color}>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
{arrayToIterate.map(({rule, matched}, index) => {
|
{arrayToIterate.map(({rule, matched}, index) => {
|
||||||
return (
|
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>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</HAREntrySectionContainer>
|
</EntrySectionContainer>
|
||||||
</> : <span/>
|
</> : <span/>
|
||||||
}
|
}
|
||||||
</React.Fragment>
|
</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
|
font-family: "Source Sans Pro", Lucida Grande, Tahoma, sans-serif
|
||||||
height: 100%
|
height: 100%
|
||||||
width: 100%
|
width: 100%
|
@ -1,7 +1,7 @@
|
|||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import styles from './HAREntryViewer.module.sass';
|
import styles from './EntryViewer.module.sass';
|
||||||
import Tabs from "../Tabs";
|
import Tabs from "../UI/Tabs";
|
||||||
import {HAREntryTableSection, HAREntryBodySection, HAREntryTablePolicySection} from "./HAREntrySections";
|
import {EntryTableSection, EntryBodySection, EntryTablePolicySection} from "./EntrySections";
|
||||||
|
|
||||||
const SectionsRepresentation: React.FC<any> = ({data, color}) => {
|
const SectionsRepresentation: React.FC<any> = ({data, color}) => {
|
||||||
const sections = []
|
const sections = []
|
||||||
@ -11,12 +11,12 @@ const SectionsRepresentation: React.FC<any> = ({data, color}) => {
|
|||||||
switch (row.type) {
|
switch (row.type) {
|
||||||
case "table":
|
case "table":
|
||||||
sections.push(
|
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;
|
break;
|
||||||
case "body":
|
case "body":
|
||||||
sections.push(
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -49,7 +49,7 @@ const AutoRepresentation: React.FC<any> = ({representation, color, isResponseMoc
|
|||||||
|
|
||||||
const {request, response} = JSON.parse(representation);
|
const {request, response} = JSON.parse(representation);
|
||||||
|
|
||||||
return <div className={styles.harEntry}>
|
return <div className={styles.Entry}>
|
||||||
{<div className={styles.body}>
|
{<div className={styles.body}>
|
||||||
<div className={styles.bodyHeader}>
|
<div className={styles.bodyHeader}>
|
||||||
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned/>
|
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned/>
|
||||||
@ -63,7 +63,7 @@ const AutoRepresentation: React.FC<any> = ({representation, color, isResponseMoc
|
|||||||
</React.Fragment>}
|
</React.Fragment>}
|
||||||
{currentTab === TABS[2].tab && <React.Fragment>
|
{currentTab === TABS[2].tab && <React.Fragment>
|
||||||
{// FIXME: Fix here
|
{// 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>}
|
</React.Fragment>}
|
||||||
</div>}
|
</div>}
|
||||||
</div>;
|
</div>;
|
||||||
@ -76,8 +76,8 @@ interface Props {
|
|||||||
showTitle?: boolean;
|
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}/>
|
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
|
.row
|
||||||
display: flex
|
display: flex
|
@ -1,16 +1,16 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import styles from './style/HarEntry.module.sass';
|
import styles from './EntryListItem.module.sass';
|
||||||
import StatusCode, {getClassification, StatusCodeClassification} from "./StatusCode";
|
import StatusCode, {getClassification, StatusCodeClassification} from "../UI/StatusCode";
|
||||||
import Protocol, {ProtocolInterface} from "./Protocol"
|
import Protocol, {ProtocolInterface} from "../UI/Protocol"
|
||||||
import {EndpointPath} from "./EndpointPath";
|
import {EndpointPath} from "../UI/EndpointPath";
|
||||||
import ingoingIconSuccess from "./assets/ingoing-traffic-success.svg"
|
import ingoingIconSuccess from "../assets/ingoing-traffic-success.svg"
|
||||||
import ingoingIconFailure from "./assets/ingoing-traffic-failure.svg"
|
import ingoingIconFailure from "../assets/ingoing-traffic-failure.svg"
|
||||||
import ingoingIconNeutral from "./assets/ingoing-traffic-neutral.svg"
|
import ingoingIconNeutral from "../assets/ingoing-traffic-neutral.svg"
|
||||||
import outgoingIconSuccess from "./assets/outgoing-traffic-success.svg"
|
import outgoingIconSuccess from "../assets/outgoing-traffic-success.svg"
|
||||||
import outgoingIconFailure from "./assets/outgoing-traffic-failure.svg"
|
import outgoingIconFailure from "../assets/outgoing-traffic-failure.svg"
|
||||||
import outgoingIconNeutral from "./assets/outgoing-traffic-neutral.svg"
|
import outgoingIconNeutral from "../assets/outgoing-traffic-neutral.svg"
|
||||||
|
|
||||||
interface HAREntry {
|
interface Entry {
|
||||||
protocol: ProtocolInterface,
|
protocol: ProtocolInterface,
|
||||||
method?: string,
|
method?: string,
|
||||||
summary: string,
|
summary: string,
|
||||||
@ -34,13 +34,13 @@ interface Rules {
|
|||||||
numberOfRules: number;
|
numberOfRules: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HAREntryProps {
|
interface EntryProps {
|
||||||
entry: HAREntry;
|
entry: Entry;
|
||||||
setFocusedEntryId: (id: string) => void;
|
setFocusedEntryId: (id: string) => void;
|
||||||
isSelected?: boolean;
|
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)
|
const classification = getClassification(entry.status_code)
|
||||||
let ingoingIcon;
|
let ingoingIcon;
|
||||||
let outgoingIcon;
|
let outgoingIcon;
|
@ -1,10 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import styles from './style/HarFilters.module.sass';
|
import styles from './style/Filters.module.sass';
|
||||||
import {HARFilterSelect} from "./HARFilterSelect";
|
import {FilterSelect} from "./UI/FilterSelect";
|
||||||
import {TextField} from "@material-ui/core";
|
import {TextField} from "@material-ui/core";
|
||||||
import {ALL_KEY} from "./Select";
|
import {ALL_KEY} from "./UI/Select";
|
||||||
|
|
||||||
interface HarFiltersProps {
|
interface FiltersProps {
|
||||||
methodsFilter: Array<string>;
|
methodsFilter: Array<string>;
|
||||||
setMethodsFilter: (methods: Array<string>) => void;
|
setMethodsFilter: (methods: Array<string>) => void;
|
||||||
statusFilter: Array<string>;
|
statusFilter: Array<string>;
|
||||||
@ -13,7 +13,7 @@ interface HarFiltersProps {
|
|||||||
setPathFilter: (val: string) => void;
|
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}>
|
return <div className={styles.container}>
|
||||||
<MethodFilter methodsFilter={methodsFilter} setMethodsFilter={setMethodsFilter}/>
|
<MethodFilter methodsFilter={methodsFilter} setMethodsFilter={setMethodsFilter}/>
|
||||||
@ -59,7 +59,7 @@ const MethodFilter: React.FC<MethodFilterProps> = ({methodsFilter, setMethodsFil
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <FilterContainer>
|
return <FilterContainer>
|
||||||
<HARFilterSelect
|
<FilterSelect
|
||||||
items={Object.values(HTTPMethod)}
|
items={Object.values(HTTPMethod)}
|
||||||
allowMultiple={true}
|
allowMultiple={true}
|
||||||
value={methodsFilter}
|
value={methodsFilter}
|
||||||
@ -91,7 +91,7 @@ const StatusTypesFilter: React.FC<StatusTypesFilterProps> = ({statusFilter, setS
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <FilterContainer>
|
return <FilterContainer>
|
||||||
<HARFilterSelect
|
<FilterSelect
|
||||||
items={Object.values(StatusType)}
|
items={Object.values(StatusType)}
|
||||||
allowMultiple={true}
|
allowMultiple={true}
|
||||||
value={statusFilter}
|
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 React, {useEffect, useRef, useState} from "react";
|
||||||
import {HarFilters} from "./HarFilters";
|
import {Filters} from "./Filters";
|
||||||
import {HarEntriesList} from "./HarEntriesList";
|
import {EntriesList} from "./EntriesList";
|
||||||
import {makeStyles} from "@material-ui/core";
|
import {makeStyles} from "@material-ui/core";
|
||||||
import "./style/HarPage.sass";
|
import "./style/TrafficPage.sass";
|
||||||
import styles from './style/HarEntriesList.module.sass';
|
import styles from './style/EntriesList.module.sass';
|
||||||
import {HAREntryDetailed} from "./HarEntryDetailed";
|
import {EntryDetailed} from "./EntryDetailed";
|
||||||
import playIcon from './assets/run.svg';
|
import playIcon from './assets/run.svg';
|
||||||
import pauseIcon from './assets/pause.svg';
|
import pauseIcon from './assets/pause.svg';
|
||||||
import variables from './style/variables.module.scss';
|
import variables from '../variables.module.scss';
|
||||||
import {StatusBar} from "./StatusBar";
|
import {StatusBar} from "./UI/StatusBar";
|
||||||
import Api, {MizuWebsocketURL} from "../helpers/api";
|
import Api, {MizuWebsocketURL} from "../helpers/api";
|
||||||
|
|
||||||
const useLayoutStyles = makeStyles(() => ({
|
const useLayoutStyles = makeStyles(() => ({
|
||||||
@ -21,7 +21,7 @@ const useLayoutStyles = makeStyles(() => ({
|
|||||||
background: variables.headerBackgoundColor
|
background: variables.headerBackgoundColor
|
||||||
},
|
},
|
||||||
|
|
||||||
harViewer: {
|
viewer: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
height: "calc(100% - 70px)",
|
height: "calc(100% - 70px)",
|
||||||
@ -36,20 +36,20 @@ enum ConnectionStatus {
|
|||||||
Paused
|
Paused
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HarPageProps {
|
interface TrafficPageProps {
|
||||||
setAnalyzeStatus: (status: any) => void;
|
setAnalyzeStatus: (status: any) => void;
|
||||||
onTLSDetected: (destAddress: string) => void;
|
onTLSDetected: (destAddress: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const api = new Api();
|
const api = new Api();
|
||||||
|
|
||||||
export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected}) => {
|
export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLSDetected}) => {
|
||||||
|
|
||||||
const classes = useLayoutStyles();
|
const classes = useLayoutStyles();
|
||||||
|
|
||||||
const [entries, setEntries] = useState([] as any);
|
const [entries, setEntries] = useState([] as any);
|
||||||
const [focusedEntryId, setFocusedEntryId] = useState(null);
|
const [focusedEntryId, setFocusedEntryId] = useState(null);
|
||||||
const [selectedHarEntry, setSelectedHarEntry] = useState(null);
|
const [selectedEntryData, setSelectedEntryData] = useState(null);
|
||||||
const [connection, setConnection] = useState(ConnectionStatus.Closed);
|
const [connection, setConnection] = useState(ConnectionStatus.Closed);
|
||||||
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
|
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
|
||||||
const [noMoreDataBottom, setNoMoreDataBottom] = useState(false);
|
const [noMoreDataBottom, setNoMoreDataBottom] = useState(false);
|
||||||
@ -129,11 +129,11 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!focusedEntryId) return;
|
if (!focusedEntryId) return;
|
||||||
setSelectedHarEntry(null);
|
setSelectedEntryData(null);
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const entryData = await api.getEntry(focusedEntryId);
|
const entryData = await api.getEntry(focusedEntryId);
|
||||||
setSelectedHarEntry(entryData);
|
setSelectedEntryData(entryData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
@ -172,14 +172,14 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isScrollable = (element) => {
|
const isScrollable = (element) => {
|
||||||
return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
|
return element.scrollHeight > element.clientHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="HarPage">
|
<div className="TrafficPage">
|
||||||
<div className="harPageHeader">
|
<div className="TrafficPageHeader">
|
||||||
<img style={{cursor: "pointer", marginRight: 15, height: 30}} alt="pause"
|
<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">
|
<div className="connectionText">
|
||||||
{getConnectionTitle()}
|
{getConnectionTitle()}
|
||||||
<div className={"indicatorContainer " + getConnectionStatusClass(true)}>
|
<div className={"indicatorContainer " + getConnectionStatusClass(true)}>
|
||||||
@ -187,9 +187,9 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{entries.length > 0 && <div className="HarPage-Container">
|
{entries.length > 0 && <div className="TrafficPage-Container">
|
||||||
<div className="HarPage-ListContainer">
|
<div className="TrafficPage-ListContainer">
|
||||||
<HarFilters methodsFilter={methodsFilter}
|
<Filters methodsFilter={methodsFilter}
|
||||||
setMethodsFilter={setMethodsFilter}
|
setMethodsFilter={setMethodsFilter}
|
||||||
statusFilter={statusFilter}
|
statusFilter={statusFilter}
|
||||||
setStatusFilter={setStatusFilter}
|
setStatusFilter={setStatusFilter}
|
||||||
@ -197,7 +197,7 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
|||||||
setPathFilter={setPathFilter}
|
setPathFilter={setPathFilter}
|
||||||
/>
|
/>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<HarEntriesList entries={entries}
|
<EntriesList entries={entries}
|
||||||
setEntries={setEntries}
|
setEntries={setEntries}
|
||||||
focusedEntryId={focusedEntryId}
|
focusedEntryId={focusedEntryId}
|
||||||
setFocusedEntryId={setFocusedEntryId}
|
setFocusedEntryId={setFocusedEntryId}
|
||||||
@ -216,8 +216,7 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.details}>
|
<div className={classes.details}>
|
||||||
{selectedHarEntry &&
|
{selectedEntryData && <EntryDetailed entryData={selectedEntryData}/>}
|
||||||
<HAREntryDetailed harEntry={selectedHarEntry} classes={{root: classes.harViewer}}/>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
{tappingStatus?.pods != null && <StatusBar tappingStatus={tappingStatus}/>}
|
{tappingStatus?.pods != null && <StatusBar tappingStatus={tappingStatus}/>}
|
@ -1,6 +1,6 @@
|
|||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import collapsedImg from "./assets/collapsed.svg";
|
import collapsedImg from "../assets/collapsed.svg";
|
||||||
import expandedImg from "./assets/expanded.svg";
|
import expandedImg from "../assets/expanded.svg";
|
||||||
import "./style/CollapsibleContainer.sass";
|
import "./style/CollapsibleContainer.sass";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||||
import duplicateImg from "./assets/duplicate.svg";
|
import duplicateImg from "../assets/duplicate.svg";
|
||||||
import './style/FancyTextDisplay.sass';
|
import './style/FancyTextDisplay.sass';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { MenuItem } from '@material-ui/core';
|
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";
|
import { Select, SelectProps } from "./Select";
|
||||||
|
|
||||||
interface HARFilterSelectProps extends SelectProps {
|
interface FilterSelectProps extends SelectProps {
|
||||||
items: string[];
|
items: string[];
|
||||||
value: string | string[];
|
value: string | string[];
|
||||||
onChange: (string) => void;
|
onChange: (string) => void;
|
||||||
@ -12,7 +12,7 @@ interface HARFilterSelectProps extends SelectProps {
|
|||||||
transformDisplay?: (string) => string;
|
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
|
return <Select
|
||||||
value={value}
|
value={value}
|
||||||
multiple={allowMultiple}
|
multiple={allowMultiple}
|
||||||
@ -20,7 +20,7 @@ export const HARFilterSelect: React.FC<HARFilterSelectProps> = ({items, value, o
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
transformDisplay={transformDisplay}
|
transformDisplay={transformDisplay}
|
||||||
labelOnTop={true}
|
labelOnTop={true}
|
||||||
labelClassName={style.HARSelectLabel}
|
labelClassName={style.SelectLabel}
|
||||||
trimItemsWhenMultiple={true}
|
trimItemsWhenMultiple={true}
|
||||||
>
|
>
|
||||||
{items?.map(item => <MenuItem key={item} value={item}><span className='uppercase'>{item}</span></MenuItem>)}
|
{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 {MenuItem, Select as MUISelect} from '@material-ui/core';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {SelectProps as MUISelectProps} from '@material-ui/core/Select/Select';
|
import {SelectProps as MUISelectProps} from '@material-ui/core/Select/Select';
|
@ -7,11 +7,11 @@ export enum StatusCodeClassification {
|
|||||||
NEUTRAL = "neutral"
|
NEUTRAL = "neutral"
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HAREntryProps {
|
interface EntryProps {
|
||||||
statusCode: number
|
statusCode: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusCode: React.FC<HAREntryProps> = ({statusCode}) => {
|
const StatusCode: React.FC<EntryProps> = ({statusCode}) => {
|
||||||
|
|
||||||
const classification = getClassification(statusCode)
|
const classification = getClassification(statusCode)
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
import Tooltip from "./Tooltip";
|
import Tooltip from "./Tooltip";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {makeStyles} from '@material-ui/core/styles';
|
import {makeStyles} from '@material-ui/core/styles';
|
||||||
import variables from './style/variables.module.scss';
|
import variables from '../../variables.module.scss';
|
||||||
|
|
||||||
interface Tab {
|
interface Tab {
|
||||||
tab: string,
|
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
|
.base
|
||||||
display: inline-block
|
display: inline-block
|
||||||
text-align: center
|
text-align: center
|
@ -1,4 +1,4 @@
|
|||||||
@import 'variables.module.scss'
|
@import '../../../variables.module'
|
||||||
|
|
||||||
.statusBar
|
.statusBar
|
||||||
position: absolute
|
position: absolute
|
@ -1,4 +1,4 @@
|
|||||||
@import 'variables.module'
|
@import '../../../variables.module'
|
||||||
|
|
||||||
.base
|
.base
|
||||||
border-radius: 4px
|
border-radius: 4px
|
@ -1,4 +1,4 @@
|
|||||||
@import 'variables.module'
|
@import '../../../variables.module'
|
||||||
|
|
||||||
.protocol
|
.protocol
|
||||||
border-radius: 4px
|
border-radius: 4px
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 301 B |
@ -1,4 +1,4 @@
|
|||||||
@import "variables.module"
|
@import "../../variables.module"
|
||||||
|
|
||||||
.list
|
.list
|
||||||
overflow: scroll
|
overflow: scroll
|
@ -1,4 +1,4 @@
|
|||||||
@import "variables.module"
|
@import "../../variables.module"
|
||||||
|
|
||||||
.container
|
.container
|
||||||
display: flex
|
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%
|
width: 100%
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
@ -8,34 +8,34 @@
|
|||||||
flex-grow: 1
|
flex-grow: 1
|
||||||
height: calc(100vh - 70px)
|
height: calc(100vh - 70px)
|
||||||
|
|
||||||
.harPageHeader
|
.TrafficPageHeader
|
||||||
padding: 20px 24px
|
padding: 20px 24px
|
||||||
display: flex
|
display: flex
|
||||||
align-items: center
|
align-items: center
|
||||||
background-color: $header-background-color
|
background-color: $header-background-color
|
||||||
|
|
||||||
.HarPage-Header
|
.TrafficPage-Header
|
||||||
display: flex
|
display: flex
|
||||||
height: 2.5%
|
height: 2.5%
|
||||||
justify-content: space-between
|
justify-content: space-between
|
||||||
align-items: center
|
align-items: center
|
||||||
padding: 18px 15px
|
padding: 18px 15px
|
||||||
|
|
||||||
.HarPage-Header-Image
|
.TrafficPage-Header-Image
|
||||||
width: 22px
|
width: 22px
|
||||||
height: 22px
|
height: 22px
|
||||||
|
|
||||||
.HarPage-Header-Text
|
.TrafficPage-Header-Text
|
||||||
margin-left: 10px
|
margin-left: 10px
|
||||||
font-family: 'Source Sans Pro', serif
|
font-family: 'Source Sans Pro', serif
|
||||||
font-size: 14px
|
font-size: 14px
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
color: #f7f9fc
|
color: #f7f9fc
|
||||||
|
|
||||||
.HarPage-Header-Actions
|
.TrafficPage-Header-Actions
|
||||||
margin-left: auto
|
margin-left: auto
|
||||||
|
|
||||||
.HarPage-Header-Actions-Image
|
.TrafficPage-Header-Actions-Image
|
||||||
width: 22px
|
width: 22px
|
||||||
height: 22px
|
height: 22px
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
@ -43,7 +43,7 @@
|
|||||||
margin-left: auto
|
margin-left: auto
|
||||||
transform: translate(0 ,25%)
|
transform: translate(0 ,25%)
|
||||||
|
|
||||||
.HarPage-Viewer
|
.TrafficPage-Viewer
|
||||||
height: 96.5%
|
height: 96.5%
|
||||||
overflow: auto
|
overflow: auto
|
||||||
|
|
||||||
@ -53,25 +53,25 @@
|
|||||||
display: block
|
display: block
|
||||||
overflow-y: auto
|
overflow-y: auto
|
||||||
|
|
||||||
.harContent
|
.TrafficContent
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
height: calc(100% - 60px)
|
height: calc(100% - 60px)
|
||||||
overflow: scroll
|
overflow: scroll
|
||||||
|
|
||||||
.HarPage-Container
|
.TrafficPage-Container
|
||||||
display: flex
|
display: flex
|
||||||
flex-grow: 1
|
flex-grow: 1
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
background-color: $data-background-color
|
background-color: $data-background-color
|
||||||
|
|
||||||
.HarPage-ListContainer
|
.TrafficPage-ListContainer
|
||||||
display: flex
|
display: flex
|
||||||
flex-grow: 1
|
flex-grow: 1
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
padding-left: 24px
|
padding-left: 24px
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
|
|
||||||
.HarPage-DetailContainer
|
.TrafficPage-DetailContainer
|
||||||
width: 45vw
|
width: 45vw
|
||||||
background-color: #171c30
|
background-color: #171c30
|
||||||
flex: 0 0 50%
|
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,
|
html,
|
||||||
body
|
body
|
||||||
|
Loading…
Reference in New Issue
Block a user