mirror of
https://github.com/kubeshark/kubeshark.git
synced 2025-07-21 11:40:56 +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
16621
ui/package-lock.json
generated
16621
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 { ServiceMapModal } from './components/ServiceMapModal/ServiceMapModal';
|
||||||
import {useRecoilState} from "recoil";
|
import {useRecoilState} from "recoil";
|
||||||
import serviceMapModalOpenAtom from "./recoil/serviceMapModalOpen";
|
import serviceMapModalOpenAtom from "./recoil/serviceMapModalOpen";
|
||||||
|
import OasModal from './components/OasModal/OasModal';
|
||||||
|
import oasModalOpenAtom from './recoil/oasModalOpen/atom';
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
|
||||||
const [analyzeStatus, setAnalyzeStatus] = useState(null);
|
const [analyzeStatus, setAnalyzeStatus] = useState(null);
|
||||||
const [serviceMapModalOpen, setServiceMapModalOpen] = useRecoilState(serviceMapModalOpenAtom);
|
const [serviceMapModalOpen, setServiceMapModalOpen] = useRecoilState(serviceMapModalOpenAtom);
|
||||||
|
const [oasModalOpen, setOasModalOpen] = useRecoilState(oasModalOpenAtom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mizuApp">
|
<div className="mizuApp">
|
||||||
@ -20,6 +23,10 @@ const App = () => {
|
|||||||
onOpen={() => setServiceMapModalOpen(true)}
|
onOpen={() => setServiceMapModalOpen(true)}
|
||||||
onClose={() => setServiceMapModalOpen(false)}
|
onClose={() => setServiceMapModalOpen(false)}
|
||||||
/>}
|
/>}
|
||||||
|
{window["isOasEnabled"] && <OasModal
|
||||||
|
openModal={oasModalOpen}
|
||||||
|
handleCloseModal={() => setOasModalOpen(false)}
|
||||||
|
/>}
|
||||||
</div>
|
</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,32 +1,40 @@
|
|||||||
import { Box, Fade, FormControl, MenuItem, Modal } from "@material-ui/core";
|
import { Box, Fade, FormControl, MenuItem, Modal, Backdrop, ListSubheader } from "@material-ui/core";
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { RedocStandalone } from "redoc";
|
import { RedocStandalone } from "redoc";
|
||||||
import Api from "../../helpers/api";
|
import Api from "../../helpers/api";
|
||||||
import { Select } from "../UI/Select";
|
import { Select } from "../UI/Select";
|
||||||
import closeIcon from "../assets/closeIcon.svg";
|
import closeIcon from "../assets/closeIcon.svg";
|
||||||
import { toast } from 'react-toastify';
|
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 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 OasModal = ({ openModal, handleCloseModal }) => {
|
||||||
const [oasServices, setOasServices] = useState([])
|
const [oasServices, setOasServices] = useState([] as string[])
|
||||||
const [selectedServiceName, setSelectedServiceName] = useState("");
|
const [selectedServiceName, setSelectedServiceName] = useState("");
|
||||||
const [selectedServiceSpec, setSelectedServiceSpec] = useState(null);
|
const [selectedServiceSpec, setSelectedServiceSpec] = useState(null);
|
||||||
|
const [resolvedServices, setResolvedServices] = useState([]);
|
||||||
|
const [unResolvedServices, setUnResolvedServices] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
const onSelectedOASService = useCallback( async (selectedService) => {
|
||||||
(async () => {
|
if (!!selectedService){
|
||||||
try {
|
|
||||||
const services = await api.getOasServices();
|
|
||||||
setOasServices(services);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, [openModal]);
|
|
||||||
|
|
||||||
const onSelectedOASService = async (selectedService) => {
|
|
||||||
setSelectedServiceName(selectedService);
|
setSelectedServiceName(selectedService);
|
||||||
if(oasServices.length === 0){
|
if(oasServices.length === 0){
|
||||||
return
|
return
|
||||||
@ -38,7 +46,41 @@ const OasModal = ({ openModal, handleCloseModal }) => {
|
|||||||
toast.error("Error occurred while fetching service OAS spec");
|
toast.error("Error occurred while fetching service OAS spec");
|
||||||
console.error(e);
|
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,resolvedArrayBuilder]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -47,29 +89,34 @@ const OasModal = ({ openModal, handleCloseModal }) => {
|
|||||||
open={openModal}
|
open={openModal}
|
||||||
onClose={handleCloseModal}
|
onClose={handleCloseModal}
|
||||||
closeAfterTransition
|
closeAfterTransition
|
||||||
hideBackdrop={true}
|
BackdropComponent={Backdrop}
|
||||||
style={{ overflow: "auto", backgroundColor: "#ffffff", color:"black" }}
|
BackdropProps={{
|
||||||
>
|
timeout: 500,
|
||||||
<Fade in={openModal}>
|
|
||||||
<Box>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
padding: "1%",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ marginLeft: "40%" }}>
|
<Fade in={openModal}>
|
||||||
|
<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>
|
<FormControl>
|
||||||
<Select
|
<Select
|
||||||
labelId="service-select-label"
|
labelId="service-select-label"
|
||||||
id="service-select"
|
id="service-select"
|
||||||
label="Show OAS"
|
|
||||||
placeholder="Show OAS"
|
placeholder="Show OAS"
|
||||||
value={selectedServiceName}
|
value={selectedServiceName}
|
||||||
onChange={onSelectedOASService}
|
onChange={onSelectedOASService}
|
||||||
>
|
>
|
||||||
{oasServices.map((service) => (
|
<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}>
|
<MenuItem key={service} value={service}>
|
||||||
{service}
|
{service}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
@ -77,13 +124,15 @@ const OasModal = ({ openModal, handleCloseModal }) => {
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div style={{ cursor: "pointer" }}>
|
<div style={{ cursor: "pointer" }}>
|
||||||
<img src={closeIcon} alt="Back" onClick={handleCloseModal} />
|
<img src={closeIcon} alt="close" onClick={handleCloseModal} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{selectedServiceSpec && <RedocStandalone spec={selectedServiceSpec} />}
|
<div className={style.redoc}>
|
||||||
<div className="NotSelectedMessage">
|
{selectedServiceSpec && <RedocStandalone
|
||||||
{!selectedServiceName && noOasServiceSelectedMessage}
|
spec={selectedServiceSpec}
|
||||||
|
options={redocThemeOptions}/>}
|
||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
</Fade>
|
</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 focusedEntryIdAtom from "../../../recoil/focusedEntryId";
|
||||||
import websocketConnectionAtom, {WsConnectionStatus} from "../../../recoil/wsConnection";
|
import websocketConnectionAtom, {WsConnectionStatus} from "../../../recoil/wsConnection";
|
||||||
import queryAtom from "../../../recoil/query";
|
import queryAtom from "../../../recoil/query";
|
||||||
import OasModal from "../../OasModal/OasModal";
|
|
||||||
import {useCommonStyles} from "../../../helpers/commonStyle"
|
import {useCommonStyles} from "../../../helpers/commonStyle"
|
||||||
import {TLSWarning} from "../../TLSWarning/TLSWarning";
|
import {TLSWarning} from "../../TLSWarning/TLSWarning";
|
||||||
import serviceMapModalOpenAtom from "../../../recoil/serviceMapModalOpen";
|
import serviceMapModalOpenAtom from "../../../recoil/serviceMapModalOpen";
|
||||||
import serviceMap from "../../assets/serviceMap.svg";
|
import serviceMap from "../../assets/serviceMap.svg";
|
||||||
import services from "../../assets/services.svg";
|
import services from "../../assets/services.svg";
|
||||||
|
import oasModalOpenAtom from "../../../recoil/oasModalOpen/atom";
|
||||||
|
|
||||||
const useLayoutStyles = makeStyles(() => ({
|
const useLayoutStyles = makeStyles(() => ({
|
||||||
details: {
|
details: {
|
||||||
@ -59,6 +59,7 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
|||||||
const [focusedEntryId, setFocusedEntryId] = useRecoilState(focusedEntryIdAtom);
|
const [focusedEntryId, setFocusedEntryId] = useRecoilState(focusedEntryIdAtom);
|
||||||
const [wsConnection, setWsConnection] = useRecoilState(websocketConnectionAtom);
|
const [wsConnection, setWsConnection] = useRecoilState(websocketConnectionAtom);
|
||||||
const setServiceMapModalOpen = useSetRecoilState(serviceMapModalOpenAtom);
|
const setServiceMapModalOpen = useSetRecoilState(serviceMapModalOpenAtom);
|
||||||
|
const [openOasModal, setOpenOasModal] = useRecoilState(oasModalOpenAtom);
|
||||||
const query = useRecoilValue(queryAtom);
|
const query = useRecoilValue(queryAtom);
|
||||||
|
|
||||||
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
|
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
|
||||||
@ -75,10 +76,6 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
|||||||
const [startTime, setStartTime] = useState(0);
|
const [startTime, setStartTime] = useState(0);
|
||||||
const scrollableRef = useRef(null);
|
const scrollableRef = useRef(null);
|
||||||
|
|
||||||
const [openOasModal, setOpenOasModal] = useState(false);
|
|
||||||
|
|
||||||
const handleCloseModal = () => setOpenOasModal(false);
|
|
||||||
|
|
||||||
const [showTLSWarning, setShowTLSWarning] = useState(false);
|
const [showTLSWarning, setShowTLSWarning] = useState(false);
|
||||||
const [userDismissedTLSWarning, setUserDismissedTLSWarning] = useState(false);
|
const [userDismissedTLSWarning, setUserDismissedTLSWarning] = useState(false);
|
||||||
const [addressesWithTLS, setAddressesWithTLS] = useState(new Set<string>());
|
const [addressesWithTLS, setAddressesWithTLS] = useState(new Set<string>());
|
||||||
@ -283,7 +280,7 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex', height: "100%" }}>
|
||||||
{window["isOasEnabled"] && <Button
|
{window["isOasEnabled"] && <Button
|
||||||
startIcon={<img className="custom" src={services} alt="services"></img>}
|
startIcon={<img className="custom" src={services} alt="services"></img>}
|
||||||
size="large"
|
size="large"
|
||||||
@ -306,10 +303,6 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus}) => {
|
|||||||
</Button>}
|
</Button>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{window["isOasEnabled"] && <OasModal
|
|
||||||
openModal={openOasModal}
|
|
||||||
handleCloseModal={handleCloseModal}
|
|
||||||
/>}
|
|
||||||
{<div className="TrafficPage-Container">
|
{<div className="TrafficPage-Container">
|
||||||
<div className="TrafficPage-ListContainer">
|
<div className="TrafficPage-ListContainer">
|
||||||
<Filters
|
<Filters
|
||||||
|
@ -81,11 +81,11 @@ interface ServiceMapModalProps {
|
|||||||
|
|
||||||
const modalStyle = {
|
const modalStyle = {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
top: '10%',
|
top: '6%',
|
||||||
left: '50%',
|
left: '50%',
|
||||||
transform: 'translate(-50%, 0%)',
|
transform: 'translate(-50%, 0%)',
|
||||||
width: '80vw',
|
width: '89vw',
|
||||||
height: '80vh',
|
height: '82vh',
|
||||||
bgcolor: 'background.paper',
|
bgcolor: 'background.paper',
|
||||||
borderRadius: '5px',
|
borderRadius: '5px',
|
||||||
boxShadow: 24,
|
boxShadow: 24,
|
||||||
|
@ -2,7 +2,6 @@ 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 '../../variables.module.scss';
|
import variables from '../../variables.module.scss';
|
||||||
|
|
||||||
interface Tab {
|
interface Tab {
|
||||||
tab: string,
|
tab: string,
|
||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
@ -40,7 +39,7 @@ const useTabsStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
|
|
||||||
active: {
|
active: {
|
||||||
fontWeight: theme.typography.fontWeightBold,
|
fontWeight: 600,
|
||||||
color: variables.fontColor,
|
color: variables.fontColor,
|
||||||
cursor: 'unset',
|
cursor: 'unset',
|
||||||
borderBottom: "2px solid " + variables.fontColor,
|
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;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gelAlloasServicesInOneSpec = async () => {
|
||||||
|
const response = await this.client.get("/oas/all");
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
validateQuery = async (query) => {
|
validateQuery = async (query) => {
|
||||||
if (this.source) {
|
if (this.source) {
|
||||||
this.source.cancel();
|
this.source.cancel();
|
||||||
|
@ -146,3 +146,11 @@ button
|
|||||||
|
|
||||||
::-webkit-scrollbar-corner
|
::-webkit-scrollbar-corner
|
||||||
display: none
|
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