mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-02-15 18:39:58 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
274fbeb34a | ||
|
|
38c05a6634 | ||
|
|
d857935889 |
@@ -6,6 +6,7 @@ import { ReactComponent as ReplayIcon } from './replay.svg';
|
||||
import styles from './EntryViewer.module.sass';
|
||||
import { Tabs } from "../../UI";
|
||||
import replayRequestModalOpenAtom from "../../../recoil/replayRequestModalOpen";
|
||||
import entryDetailedConfigAtom, { EntryDetailedConfig } from "../../../recoil/entryDetailedConfig";
|
||||
|
||||
const enabledProtocolsForReplay = ["http"]
|
||||
|
||||
@@ -16,10 +17,11 @@ export enum TabsEnum {
|
||||
|
||||
export const AutoRepresentation: React.FC<any> = ({ representation, color, openedTab = TabsEnum.Request, isDisplayReplay = false }) => {
|
||||
const entryData = useRecoilValue(entryDataAtom)
|
||||
const { isReplayEnabled } = useRecoilValue<EntryDetailedConfig>(entryDetailedConfigAtom)
|
||||
const setIsOpenRequestModal = useSetRecoilState(replayRequestModalOpenAtom)
|
||||
const isReplayDisplayed = useCallback(() => {
|
||||
return enabledProtocolsForReplay.find(x => x === entryData.protocol.name) && isDisplayReplay
|
||||
}, [entryData.protocol.name, isDisplayReplay])
|
||||
return enabledProtocolsForReplay.find(x => x === entryData.protocol.name) && isDisplayReplay && isReplayEnabled
|
||||
}, [entryData.protocol.name, isDisplayReplay, isReplayEnabled])
|
||||
|
||||
const { request, response } = JSON.parse(representation);
|
||||
|
||||
@@ -27,20 +29,18 @@ export const AutoRepresentation: React.FC<any> = ({ representation, color, opene
|
||||
const arr = [
|
||||
{
|
||||
tab: 'Request',
|
||||
badge: isReplayDisplayed() && <span title="Replay Request"><ReplayIcon fill={color} stroke={color} style={{ marginLeft: "10px", cursor: "pointer", height: "22px" }} onClick={() => setIsOpenRequestModal(true)} /></span>
|
||||
badge: null
|
||||
}]
|
||||
|
||||
if (response) {
|
||||
arr.push(
|
||||
{
|
||||
tab: 'Response',
|
||||
badge: null
|
||||
}
|
||||
);
|
||||
arr.push({
|
||||
tab: 'Response',
|
||||
badge: null
|
||||
});
|
||||
}
|
||||
|
||||
return arr
|
||||
}, [color, isReplayDisplayed, response, setIsOpenRequestModal]);
|
||||
}, [response]);
|
||||
|
||||
const [currentTab, setCurrentTab] = useState(TABS[0].tab);
|
||||
|
||||
@@ -66,6 +66,7 @@ export const AutoRepresentation: React.FC<any> = ({ representation, color, opene
|
||||
{<div className={styles.body}>
|
||||
<div className={styles.bodyHeader}>
|
||||
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned />
|
||||
{isReplayDisplayed() && <span title="Replay Request"><ReplayIcon fill={color} stroke={color} style={{ marginLeft: "10px", cursor: "pointer", height: "22px" }} onClick={() => setIsOpenRequestModal(true)} /></span>}
|
||||
</div>
|
||||
{getOpenedTabIndex() === TabsEnum.Request && <React.Fragment>
|
||||
<SectionsRepresentation data={request} color={color} requestRepresentation={request} />
|
||||
|
||||
@@ -52,8 +52,13 @@
|
||||
border-radius: 4px
|
||||
padding: 10px
|
||||
position: relative
|
||||
|
||||
.bodyHeader
|
||||
padding: 0 1rem
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
|
||||
.endpointURL
|
||||
font-size: .75rem
|
||||
display: block
|
||||
|
||||
@@ -22,6 +22,7 @@ import leftOffTopAtom from "../../recoil/leftOffTop";
|
||||
import { DEFAULT_LEFTOFF, DEFAULT_FETCH, DEFAULT_FETCH_TIMEOUT_MS } from '../../hooks/useWS';
|
||||
import ReplayRequestModalContainer from "../modals/ReplayRequestModal/ReplayRequestModal";
|
||||
import replayRequestModalOpenAtom from "../../recoil/replayRequestModalOpen";
|
||||
import entryDetailedConfigAtom, { EntryDetailedConfig } from "../../recoil/entryDetailedConfig";
|
||||
|
||||
const useLayoutStyles = makeStyles(() => ({
|
||||
details: {
|
||||
@@ -51,18 +52,22 @@ interface TrafficViewerProps {
|
||||
webSocketUrl: string,
|
||||
shouldCloseWebSocket: boolean,
|
||||
setShouldCloseWebSocket: (flag: boolean) => void,
|
||||
isDemoBannerView: boolean
|
||||
isDemoBannerView: boolean,
|
||||
entryDetailedConfig: EntryDetailedConfig
|
||||
}
|
||||
|
||||
export const TrafficViewer: React.FC<TrafficViewerProps> = ({
|
||||
trafficViewerApiProp,
|
||||
actionButtons, isShowStatusBar, webSocketUrl,
|
||||
shouldCloseWebSocket, setShouldCloseWebSocket, isDemoBannerView
|
||||
}) => {
|
||||
trafficViewerApiProp,
|
||||
webSocketUrl,
|
||||
actionButtons,
|
||||
isShowStatusBar, isDemoBannerView,
|
||||
shouldCloseWebSocket, setShouldCloseWebSocket,
|
||||
entryDetailedConfig }) => {
|
||||
|
||||
const classes = useLayoutStyles();
|
||||
const setEntries = useSetRecoilState(entriesAtom);
|
||||
const setFocusedEntryId = useSetRecoilState(focusedEntryIdAtom);
|
||||
const setEntryDetailedConfigAtom = useSetRecoilState(entryDetailedConfigAtom)
|
||||
const query = useRecoilValue(queryAtom);
|
||||
const setTrafficViewerApiState = useSetRecoilState(trafficViewerApiAtom as RecoilState<TrafficViewerApi>)
|
||||
const [tappingStatus, setTappingStatus] = useRecoilState(tappingStatusAtom);
|
||||
@@ -183,6 +188,10 @@ export const TrafficViewer: React.FC<TrafficViewerProps> = ({
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setEntryDetailedConfigAtom(entryDetailedConfig)
|
||||
}, [entryDetailedConfig, setEntryDetailedConfigAtom])
|
||||
|
||||
const getConnectionIndicator = () => {
|
||||
switch (wsReadyState) {
|
||||
case WebSocket.OPEN:
|
||||
@@ -258,7 +267,7 @@ export const TrafficViewer: React.FC<TrafficViewerProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.details} id="rightSideContainer">
|
||||
<EntryDetailed/>
|
||||
<EntryDetailed />
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
@@ -266,25 +275,19 @@ export const TrafficViewer: React.FC<TrafficViewerProps> = ({
|
||||
};
|
||||
|
||||
const MemorizedTrafficViewer = React.memo(TrafficViewer)
|
||||
const TrafficViewerContainer: React.FC<TrafficViewerProps> = ({
|
||||
trafficViewerApiProp,
|
||||
actionButtons, isShowStatusBar = true,
|
||||
webSocketUrl, shouldCloseWebSocket, setShouldCloseWebSocket, isDemoBannerView
|
||||
}) => {
|
||||
const TrafficViewerContainer: React.FC<TrafficViewerProps> = (props) => {
|
||||
return <RecoilRoot>
|
||||
<MemorizedTrafficViewer actionButtons={actionButtons} isShowStatusBar={isShowStatusBar} webSocketUrl={webSocketUrl}
|
||||
shouldCloseWebSocket={shouldCloseWebSocket} setShouldCloseWebSocket={setShouldCloseWebSocket} trafficViewerApiProp={trafficViewerApiProp}
|
||||
isDemoBannerView={isDemoBannerView}/>
|
||||
<MemorizedTrafficViewer {...props} />
|
||||
<ToastContainer enableMultiContainer containerId={TOAST_CONTAINER_ID}
|
||||
position="bottom-right"
|
||||
autoClose={5000}
|
||||
hideProgressBar={false}
|
||||
newestOnTop={false}
|
||||
closeOnClick
|
||||
rtl={false}
|
||||
pauseOnFocusLoss
|
||||
draggable
|
||||
pauseOnHover/>
|
||||
position="bottom-right"
|
||||
autoClose={5000}
|
||||
hideProgressBar={false}
|
||||
newestOnTop={false}
|
||||
closeOnClick
|
||||
rtl={false}
|
||||
pauseOnFocusLoss
|
||||
draggable
|
||||
pauseOnHover />
|
||||
<ReplayRequestModalContainer />
|
||||
</RecoilRoot>
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ $modalMargin-from-edge : 35px
|
||||
width: -moz-available
|
||||
width: -webkit-fill-available
|
||||
width: fill-available
|
||||
width: strech
|
||||
max-width: 200px
|
||||
box-shadow: 0px 1px 5px #979797
|
||||
margin-left: 10px
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import styles from "./TimelineBarChart.module.sass";
|
||||
import { ALL_PROTOCOLS, StatsMode } from "../TrafficStatsModal"
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
BarChart,
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
Tooltip,
|
||||
} from "recharts";
|
||||
import { Utils } from "../../../../helpers/Utils";
|
||||
import { ALL_PROTOCOLS, StatsMode } from "../consts";
|
||||
|
||||
interface TimelineBarChartProps {
|
||||
timeLineBarChartMode: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Cell, Legend, Pie, PieChart, Tooltip } from "recharts";
|
||||
import { Utils } from "../../../../helpers/Utils";
|
||||
import { ALL_PROTOCOLS, StatsMode as PieChartMode } from "../TrafficStatsModal"
|
||||
import { ALL_PROTOCOLS ,StatsMode as PieChartMode } from "../consts"
|
||||
|
||||
const RADIAN = Math.PI / 180;
|
||||
const renderCustomizedLabel = ({
|
||||
|
||||
@@ -7,6 +7,7 @@ import { TimelineBarChart } from "./TimelineBarChart/TimelineBarChart";
|
||||
import refreshIcon from "assets/refresh.svg";
|
||||
import { useCommonStyles } from "../../../helpers/commonStyle";
|
||||
import { LoadingWrapper } from "../../UI/withLoading/withLoading";
|
||||
import { ALL_PROTOCOLS, StatsMode } from "./consts";
|
||||
|
||||
const modalStyle = {
|
||||
position: 'absolute',
|
||||
@@ -22,19 +23,12 @@ const modalStyle = {
|
||||
color: '#000',
|
||||
};
|
||||
|
||||
export enum StatsMode {
|
||||
REQUESTS = "entriesCount",
|
||||
VOLUME = "volumeSizeBytes"
|
||||
}
|
||||
|
||||
interface TrafficStatsModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
getTrafficStatsDataApi: () => Promise<any>
|
||||
}
|
||||
|
||||
export const ALL_PROTOCOLS = "ALL";
|
||||
|
||||
export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, onClose, getTrafficStatsDataApi }) => {
|
||||
|
||||
const modes = Object.keys(StatsMode).filter(x => !(parseInt(x) >= 0));
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export const ALL_PROTOCOLS = "ALL";
|
||||
export enum StatsMode {
|
||||
REQUESTS = "entriesCount",
|
||||
VOLUME = "volumeSizeBytes"
|
||||
}
|
||||
@@ -7,6 +7,5 @@ import { ServiceMapModal } from './components/modals/ServiceMapModal/ServiceMapM
|
||||
import { TrafficStatsModal } from './components/modals/TrafficStatsModal/TrafficStatsModal';
|
||||
|
||||
export { CodeEditorWrap as QueryForm } from './components/Filters/Filters';
|
||||
export { UI, StatusBar, OasModal, ServiceMapModal, TrafficStatsModal }
|
||||
export { UI, StatusBar, OasModal, ServiceMapModal, TrafficStatsModal, TrafficViewer }
|
||||
export { useWS, DEFAULT_LEFTOFF }
|
||||
export default TrafficViewer;
|
||||
|
||||
12
ui-common/src/recoil/entryDetailedConfig/atom.ts
Normal file
12
ui-common/src/recoil/entryDetailedConfig/atom.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { atom } from "recoil";
|
||||
|
||||
const entryDetailedConfigAtom = atom({
|
||||
key: "entryDetailedConfigAtom",
|
||||
default: null
|
||||
});
|
||||
|
||||
export type EntryDetailedConfig = {
|
||||
isReplayEnabled: boolean
|
||||
}
|
||||
|
||||
export default entryDetailedConfigAtom;
|
||||
3
ui-common/src/recoil/entryDetailedConfig/index.ts
Normal file
3
ui-common/src/recoil/entryDetailedConfig/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import atom from "./atom"
|
||||
export type { EntryDetailedConfig } from "./atom"
|
||||
export default atom
|
||||
@@ -5,13 +5,14 @@ import debounce from 'lodash/debounce';
|
||||
import { useRecoilState } from "recoil";
|
||||
import { useCommonStyles } from "../../../helpers/commonStyle"
|
||||
import serviceMapModalOpenAtom from "../../../recoil/serviceMapModalOpen";
|
||||
import TrafficViewer from "@up9/mizu-common"
|
||||
import { TrafficViewer } from "@up9/mizu-common"
|
||||
import "@up9/mizu-common/dist/index.css"
|
||||
import oasModalOpenAtom from "../../../recoil/oasModalOpen/atom";
|
||||
import serviceMap from "../../assets/serviceMap.svg";
|
||||
import services from "../../assets/services.svg";
|
||||
import trafficStatsIcon from "../../assets/trafficStats.svg";
|
||||
import trafficStatsModalOpenAtom from "../../../recoil/trafficStatsModalOpen";
|
||||
import { REPLAY_ENABLED } from "../../../consts";
|
||||
|
||||
const api = Api.getInstance();
|
||||
|
||||
@@ -40,39 +41,41 @@ export const TrafficPage: React.FC = () => {
|
||||
}, 500);
|
||||
|
||||
const actionButtons = <div style={{ display: 'flex', height: "100%" }}>
|
||||
{window["isOasEnabled"] && <Button
|
||||
startIcon={<img className="custom" src={services} alt="services" />}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
style={{ marginRight: 25, textTransform: 'unset' }}
|
||||
onClick={handleOpenOasModal}>
|
||||
Service Catalog
|
||||
</Button>}
|
||||
{window["isServiceMapEnabled"] && <Button
|
||||
startIcon={<img src={serviceMap} className="custom" alt="service-map" style={{ marginRight: "8%" }} />}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
onClick={openServiceMapModalDebounce}
|
||||
style={{ marginRight: 25, textTransform: 'unset' }}>
|
||||
Service Map
|
||||
</Button>}
|
||||
{window["isOasEnabled"] && <Button
|
||||
startIcon={<img className="custom" src={services} alt="services" />}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
style={{ marginRight: 25, textTransform: 'unset' }}
|
||||
onClick={handleOpenOasModal}>
|
||||
Service Catalog
|
||||
</Button>}
|
||||
{window["isServiceMapEnabled"] && <Button
|
||||
startIcon={<img src={serviceMap} className="custom" alt="service-map" style={{ marginRight: "8%" }} />}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
onClick={openServiceMapModalDebounce}
|
||||
style={{ marginRight: 25, textTransform: 'unset' }}>
|
||||
Service Map
|
||||
</Button>}
|
||||
<Button
|
||||
startIcon={<img className="custom" src={trafficStatsIcon} alt="services" />}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
style={{ textTransform: 'unset' }}
|
||||
onClick={handleOpenStatsModal}>
|
||||
startIcon={<img className="custom" src={trafficStatsIcon} alt="services" />}
|
||||
size="large"
|
||||
variant="contained"
|
||||
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
|
||||
style={{ textTransform: 'unset' }}
|
||||
onClick={handleOpenStatsModal}>
|
||||
Traffic Stats
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
return (
|
||||
<>
|
||||
<TrafficViewer webSocketUrl={MizuWebsocketURL} shouldCloseWebSocket={shouldCloseWebSocket} setShouldCloseWebSocket={setShouldCloseWebSocket}
|
||||
trafficViewerApiProp={trafficViewerApi} actionButtons={actionButtons} isShowStatusBar={!(openOasModal || serviceMapModalOpen || trafficStatsModalOpen)} isDemoBannerView={false} />
|
||||
trafficViewerApiProp={trafficViewerApi} actionButtons={actionButtons} isShowStatusBar={!(openOasModal || serviceMapModalOpen || trafficStatsModalOpen)} isDemoBannerView={false} entryDetailedConfig={{
|
||||
isReplayEnabled: REPLAY_ENABLED
|
||||
}} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export const adminUsername = "admin";
|
||||
export const TOAST_CONTAINER_ID = "Community";
|
||||
export const REPLAY_ENABLED = true;
|
||||
|
||||
Reference in New Issue
Block a user