mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-07-19 10:48:59 +00:00
TRA-4256 gui oas window (#854)
* styling oas modal window * styled oas modal * review notes fix * oas logo added * small fixes * typo
This commit is contained in:
parent
c671bc6655
commit
c1d774e53c
16689
ui/package-lock.json
generated
16689
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -5,11 +5,14 @@ import {TrafficPage} from "./components/Pages/TrafficPage/TrafficPage";
|
||||
import { ServiceMapModal } from './components/ServiceMapModal/ServiceMapModal';
|
||||
import {useRecoilState} from "recoil";
|
||||
import serviceMapModalOpenAtom from "./recoil/serviceMapModalOpen";
|
||||
import OasModal from './components/OasModal/OasModal';
|
||||
import oasModalOpenAtom from './recoil/oasModalOpen/atom';
|
||||
|
||||
const App = () => {
|
||||
|
||||
const [analyzeStatus, setAnalyzeStatus] = useState(null);
|
||||
const [serviceMapModalOpen, setServiceMapModalOpen] = useRecoilState(serviceMapModalOpenAtom);
|
||||
const [oasModalOpen, setOasModalOpen] = useRecoilState(oasModalOpenAtom)
|
||||
|
||||
return (
|
||||
<div className="mizuApp">
|
||||
@ -20,6 +23,10 @@ const App = () => {
|
||||
onOpen={() => setServiceMapModalOpen(true)}
|
||||
onClose={() => setServiceMapModalOpen(false)}
|
||||
/>}
|
||||
{window["isOasEnabled"] && <OasModal
|
||||
openModal={oasModalOpen}
|
||||
handleCloseModal={() => setOasModalOpen(false)}
|
||||
/>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
29
ui/src/components/OasModal/OasModal.module.sass
Normal file
29
ui/src/components/OasModal/OasModal.module.sass
Normal file
@ -0,0 +1,29 @@
|
||||
@import '../../variables.module.scss'
|
||||
|
||||
.boxContainer
|
||||
display: flex
|
||||
justifyContent: space-between
|
||||
padding: 10px
|
||||
|
||||
.selectHeader
|
||||
display: flex
|
||||
align-items: center
|
||||
width: 100%
|
||||
margin-top: -1%
|
||||
|
||||
.openApilogo
|
||||
width: 36px
|
||||
|
||||
.title
|
||||
color:#494677
|
||||
font-family: Lato
|
||||
font-size: 20px
|
||||
font-weight: 600
|
||||
|
||||
.selectContainer
|
||||
margin-left: 1%
|
||||
|
||||
.redoc
|
||||
height: 98%
|
||||
overflow-y: scroll
|
||||
|
@ -1,6 +0,0 @@
|
||||
@import '../../variables.module.scss'
|
||||
|
||||
.NotSelectedMessage
|
||||
margin-left: 41%
|
||||
padding-top: 3%
|
||||
font-size: large
|
@ -1,44 +1,86 @@
|
||||
import { Box, Fade, FormControl, MenuItem, Modal } from "@material-ui/core";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Box, Fade, FormControl, MenuItem, Modal, Backdrop, ListSubheader } from "@material-ui/core";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { RedocStandalone } from "redoc";
|
||||
import Api from "../../helpers/api";
|
||||
import { Select } from "../UI/Select";
|
||||
import closeIcon from "../assets/closeIcon.svg";
|
||||
import { toast } from 'react-toastify';
|
||||
import './OasModal.sass'
|
||||
import style from './OasModal.module.sass';
|
||||
import openApiLogo from '../assets/openApiLogo.png'
|
||||
import { redocThemeOptions } from "./redocThemeOptions";
|
||||
|
||||
const modalStyle = {
|
||||
position: 'absolute',
|
||||
top: '6%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, 0%)',
|
||||
width: '89vw',
|
||||
height: '82vh',
|
||||
bgcolor: 'background.paper',
|
||||
borderRadius: '5px',
|
||||
boxShadow: 24,
|
||||
p: 4,
|
||||
color: '#000',
|
||||
};
|
||||
|
||||
const api = Api.getInstance();
|
||||
const noOasServiceSelectedMessage = "Please Select OasService";
|
||||
const ipAddressWithPortRegex = new RegExp('([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}):([0-9]{1,5})');
|
||||
|
||||
const OasModal = ({ openModal, handleCloseModal }) => {
|
||||
const [oasServices, setOasServices] = useState([])
|
||||
const [oasServices, setOasServices] = useState([] as string[])
|
||||
const [selectedServiceName, setSelectedServiceName] = useState("");
|
||||
const [selectedServiceSpec, setSelectedServiceSpec] = useState(null);
|
||||
const [resolvedServices, setResolvedServices] = useState([]);
|
||||
const [unResolvedServices, setUnResolvedServices] = useState([]);
|
||||
|
||||
const onSelectedOASService = useCallback( async (selectedService) => {
|
||||
if (!!selectedService){
|
||||
setSelectedServiceName(selectedService);
|
||||
if(oasServices.length === 0){
|
||||
return
|
||||
}
|
||||
try {
|
||||
const data = await api.getOasByService(selectedService);
|
||||
setSelectedServiceSpec(data);
|
||||
} catch (e) {
|
||||
toast.error("Error occurred while fetching service OAS spec");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
},[oasServices.length])
|
||||
|
||||
const resolvedArrayBuilder = useCallback(async(services) => {
|
||||
const resServices = [];
|
||||
const unResServices = [];
|
||||
services.forEach(s => {
|
||||
if(ipAddressWithPortRegex.test(s)){
|
||||
unResServices.push(s);
|
||||
}
|
||||
else {
|
||||
resServices.push(s);
|
||||
}
|
||||
});
|
||||
|
||||
resServices.sort();
|
||||
unResServices.sort();
|
||||
onSelectedOASService(resServices[0]);
|
||||
setResolvedServices(resServices);
|
||||
setUnResolvedServices(unResServices);
|
||||
},[onSelectedOASService])
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const services = await api.getOasServices();
|
||||
resolvedArrayBuilder(services);
|
||||
setOasServices(services);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
})();
|
||||
}, [openModal]);
|
||||
}, [openModal,resolvedArrayBuilder]);
|
||||
|
||||
|
||||
const onSelectedOASService = async (selectedService) => {
|
||||
setSelectedServiceName(selectedService);
|
||||
if(oasServices.length === 0){
|
||||
return
|
||||
}
|
||||
try {
|
||||
const data = await api.getOasByService(selectedService);
|
||||
setSelectedServiceSpec(data);
|
||||
} catch (e) {
|
||||
toast.error("Error occurred while fetching service OAS spec");
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -47,43 +89,50 @@ const OasModal = ({ openModal, handleCloseModal }) => {
|
||||
open={openModal}
|
||||
onClose={handleCloseModal}
|
||||
closeAfterTransition
|
||||
hideBackdrop={true}
|
||||
style={{ overflow: "auto", backgroundColor: "#ffffff", color:"black" }}
|
||||
BackdropComponent={Backdrop}
|
||||
BackdropProps={{
|
||||
timeout: 500,
|
||||
}}
|
||||
>
|
||||
<Fade in={openModal}>
|
||||
<Box>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
padding: "1%",
|
||||
}}
|
||||
>
|
||||
<div style={{ marginLeft: "40%" }}>
|
||||
<FormControl>
|
||||
<Select
|
||||
labelId="service-select-label"
|
||||
id="service-select"
|
||||
label="Show OAS"
|
||||
placeholder="Show OAS"
|
||||
value={selectedServiceName}
|
||||
onChange={onSelectedOASService}
|
||||
>
|
||||
{oasServices.map((service) => (
|
||||
<MenuItem key={service} value={service}>
|
||||
{service}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Box sx={modalStyle}>
|
||||
<div className={style.boxContainer}>
|
||||
<div className={style.selectHeader}>
|
||||
<div><img src={openApiLogo} alt="openApi" className={style.openApilogo}/></div>
|
||||
<div className={style.title}>OpenAPI selected service: </div>
|
||||
<div className={style.selectContainer} >
|
||||
<FormControl>
|
||||
<Select
|
||||
labelId="service-select-label"
|
||||
id="service-select"
|
||||
placeholder="Show OAS"
|
||||
value={selectedServiceName}
|
||||
onChange={onSelectedOASService}
|
||||
>
|
||||
<ListSubheader disableSticky={true}>Resolved</ListSubheader>
|
||||
{resolvedServices.map((service) => (
|
||||
<MenuItem key={service} value={service}>
|
||||
{service}
|
||||
</MenuItem>
|
||||
))}
|
||||
<ListSubheader disableSticky={true}>UnResolved</ListSubheader>
|
||||
{unResolvedServices.map((service) => (
|
||||
<MenuItem key={service} value={service}>
|
||||
{service}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ cursor: "pointer" }}>
|
||||
<img src={closeIcon} alt="Back" onClick={handleCloseModal} />
|
||||
<img src={closeIcon} alt="close" onClick={handleCloseModal} />
|
||||
</div>
|
||||
</div>
|
||||
{selectedServiceSpec && <RedocStandalone spec={selectedServiceSpec} />}
|
||||
<div className="NotSelectedMessage">
|
||||
{!selectedServiceName && noOasServiceSelectedMessage}
|
||||
<div className={style.redoc}>
|
||||
{selectedServiceSpec && <RedocStandalone
|
||||
spec={selectedServiceSpec}
|
||||
options={redocThemeOptions}/>}
|
||||
</div>
|
||||
</Box>
|
||||
</Fade>
|
||||
|
35
ui/src/components/OasModal/redocThemeOptions.ts
Normal file
35
ui/src/components/OasModal/redocThemeOptions.ts
Normal file
@ -0,0 +1,35 @@
|
||||
export const redocThemeOptions = {
|
||||
theme:{
|
||||
codeBlock:{
|
||||
backgroundColor:"#11171a",
|
||||
},
|
||||
colors:{
|
||||
responses:{
|
||||
error:{
|
||||
tabTextColor:"#1b1b29"
|
||||
},
|
||||
info:{
|
||||
tabTextColor:"#1b1b29",
|
||||
},
|
||||
success:{
|
||||
tabTextColor:"#0c0b1a"
|
||||
},
|
||||
},
|
||||
text:{
|
||||
primary:"#1b1b29",
|
||||
secondary:"#4d4d4d"
|
||||
}
|
||||
},
|
||||
rightPanel:{
|
||||
backgroundColor:"#253237",
|
||||
},
|
||||
sidebar:{
|
||||
backgroundColor:"#ffffff"
|
||||
},
|
||||
typography:{
|
||||
code:{
|
||||
color:"#0c0b1a"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -18,12 +18,12 @@ import entriesAtom from "../../../recoil/entries";
|
||||
import focusedEntryIdAtom from "../../../recoil/focusedEntryId";
|
||||
import websocketConnectionAtom, {WsConnectionStatus} from "../../../recoil/wsConnection";
|
||||
import queryAtom from "../../../recoil/query";
|
||||
import OasModal from "../../OasModal/OasModal";
|
||||
import {useCommonStyles} from "../../../helpers/commonStyle"
|
||||
import {TLSWarning} from "../../TLSWarning/TLSWarning";
|
||||
import serviceMapModalOpenAtom from "../../../recoil/serviceMapModalOpen";
|
||||
import serviceMap from "../../assets/serviceMap.svg";
|
||||
import services from "../../assets/services.svg";
|
||||
import oasModalOpenAtom from "../../../recoil/oasModalOpen/atom";
|
||||
|
||||
const useLayoutStyles = makeStyles(() => ({
|
||||
details: {
|
||||
@ -59,6 +59,7 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
||||
const [focusedEntryId, setFocusedEntryId] = useRecoilState(focusedEntryIdAtom);
|
||||
const [wsConnection, setWsConnection] = useRecoilState(websocketConnectionAtom);
|
||||
const setServiceMapModalOpen = useSetRecoilState(serviceMapModalOpenAtom);
|
||||
const [openOasModal, setOpenOasModal] = useRecoilState(oasModalOpenAtom);
|
||||
const query = useRecoilValue(queryAtom);
|
||||
|
||||
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
|
||||
@ -75,10 +76,6 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
||||
const [startTime, setStartTime] = useState(0);
|
||||
const scrollableRef = useRef(null);
|
||||
|
||||
const [openOasModal, setOpenOasModal] = useState(false);
|
||||
|
||||
const handleCloseModal = () => setOpenOasModal(false);
|
||||
|
||||
const [showTLSWarning, setShowTLSWarning] = useState(false);
|
||||
const [userDismissedTLSWarning, setUserDismissedTLSWarning] = useState(false);
|
||||
const [addressesWithTLS, setAddressesWithTLS] = useState(new Set<string>());
|
||||
@ -283,7 +280,7 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div style={{ display: 'flex', height: "100%" }}>
|
||||
{window["isOasEnabled"] && <Button
|
||||
startIcon={<img className="custom" src={services} alt="services"></img>}
|
||||
size="large"
|
||||
@ -306,10 +303,6 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
||||
</Button>}
|
||||
</div>
|
||||
</div>
|
||||
{window["isOasEnabled"] && <OasModal
|
||||
openModal={openOasModal}
|
||||
handleCloseModal={handleCloseModal}
|
||||
/>}
|
||||
{<div className="TrafficPage-Container">
|
||||
<div className="TrafficPage-ListContainer">
|
||||
<Filters
|
||||
|
@ -81,11 +81,11 @@ interface ServiceMapModalProps {
|
||||
|
||||
const modalStyle = {
|
||||
position: 'absolute',
|
||||
top: '10%',
|
||||
top: '6%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, 0%)',
|
||||
width: '80vw',
|
||||
height: '80vh',
|
||||
width: '89vw',
|
||||
height: '82vh',
|
||||
bgcolor: 'background.paper',
|
||||
borderRadius: '5px',
|
||||
boxShadow: 24,
|
||||
|
@ -2,7 +2,6 @@ import Tooltip from "./Tooltip";
|
||||
import React from "react";
|
||||
import {makeStyles} from '@material-ui/core/styles';
|
||||
import variables from '../../variables.module.scss';
|
||||
|
||||
interface Tab {
|
||||
tab: string,
|
||||
disabled?: boolean,
|
||||
@ -27,7 +26,7 @@ const useTabsStyles = makeStyles((theme) => ({
|
||||
height: 40,
|
||||
paddingTop: 15
|
||||
},
|
||||
|
||||
|
||||
tab: {
|
||||
display: 'inline-block',
|
||||
textTransform: 'uppercase',
|
||||
@ -40,7 +39,7 @@ const useTabsStyles = makeStyles((theme) => ({
|
||||
},
|
||||
|
||||
active: {
|
||||
fontWeight: theme.typography.fontWeightBold,
|
||||
fontWeight: 600,
|
||||
color: variables.fontColor,
|
||||
cursor: 'unset',
|
||||
borderBottom: "2px solid " + variables.fontColor,
|
||||
|
BIN
ui/src/components/assets/openApiLogo.png
Normal file
BIN
ui/src/components/assets/openApiLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
@ -84,6 +84,11 @@ export default class Api {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
gelAlloasServicesInOneSpec = async () => {
|
||||
const response = await this.client.get("/oas/all");
|
||||
return response.data;
|
||||
}
|
||||
|
||||
validateQuery = async (query) => {
|
||||
if (this.source) {
|
||||
this.source.cancel();
|
||||
|
@ -146,3 +146,11 @@ button
|
||||
|
||||
::-webkit-scrollbar-corner
|
||||
display: none
|
||||
|
||||
// remove powerdby
|
||||
.sc-ilfuhL
|
||||
display: none !important
|
||||
|
||||
// enable view elements inside redoc
|
||||
.sc-dwsnSq
|
||||
height: 80vh !important
|
||||
|
8
ui/src/recoil/oasModalOpen/atom.ts
Normal file
8
ui/src/recoil/oasModalOpen/atom.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { atom } from "recoil"
|
||||
|
||||
const oasModalOpenAtom = atom({
|
||||
key: "oasModalOpenAtom",
|
||||
default: false
|
||||
})
|
||||
|
||||
export default oasModalOpenAtom;
|
2
ui/src/recoil/oasModalOpen/index.ts
Normal file
2
ui/src/recoil/oasModalOpen/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import atom from "./atom";
|
||||
export default atom;
|
Loading…
Reference in New Issue
Block a user