time picker added

This commit is contained in:
Amit Fainholts 2022-07-12 18:14:04 +03:00
parent c010d336bb
commit 20d3d54b4b
10 changed files with 5118 additions and 69 deletions

File diff suppressed because it is too large Load Diff

View File

@ -26,14 +26,15 @@
"@craco/craco": "^6.4.3",
"@types/jest": "^26.0.24",
"@types/node": "^12.20.54",
"sass": "^1.52.3",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^17.0.2",
"recoil": "^0.7.2"
"recoil": "^0.7.2",
"sass": "^1.52.3"
},
"dependencies": {
"@craco/craco": "^6.4.3",
"@elastic/eui": "^60.2.0",
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/icons-material": "^5.8.2",

View File

@ -0,0 +1,91 @@
import React, { useState, Fragment } from 'react';
import {
EuiSuperDatePicker,
EuiSpacer,
} from '@elastic/eui';
import dateMath from '@elastic/datemath';
interface TimeRangePickerProps {
refreshStats: (startTime, endTime) => void;
}
export const TimeRangePicker: React.FC<TimeRangePickerProps> = ({ refreshStats }) => {
const [recentlyUsedRanges, setRecentlyUsedRanges] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [start, setStart] = useState('now-30m');
const [end, setEnd] = useState('now');
const [isPaused, setIsPaused] = useState(true);
const [refreshInterval, setRefreshInterval] = useState();
const dateConvertor = (inputStart, inputEnd) => {
const startMoment = dateMath.parse(inputStart);
if (!startMoment || !startMoment.isValid()) {
throw new Error('Unable to parse start string');
}
const endMoment = dateMath.parse(inputEnd, { roundUp: true });
if (!endMoment || !endMoment.isValid()) {
throw new Error('Unable to parse end string');
}
return { startMoment: startMoment.format("x"), endMoment: endMoment.format("x") }
}
const onTimeChange = ({ start, end }) => {
const recentlyUsedRange = recentlyUsedRanges.filter(recentlyUsedRange => {
const isDuplicate =
recentlyUsedRange.start === start && recentlyUsedRange.end === end;
return !isDuplicate;
});
recentlyUsedRange.unshift({ start, end });
setStart(start);
setEnd(end);
setRecentlyUsedRanges(
recentlyUsedRange.length > 10
? recentlyUsedRange.slice(0, 9)
: recentlyUsedRange
);
const { startMoment, endMoment } = dateConvertor(start, end)
refreshStats(startMoment, endMoment)
setIsLoading(true);
startLoading();
};
const onRefresh = ({ start, end, refreshInterval }) => {
return new Promise(resolve => {
setTimeout(resolve, 100);
}).then(() => {
const { startMoment, endMoment } = dateConvertor(start,end)
refreshStats(startMoment, endMoment)
});
};
const startLoading = () => {
setTimeout(stopLoading, 1000);
};
const stopLoading = () => {
setIsLoading(false);
};
const onRefreshChange = ({ isPaused, refreshInterval }) => {
setIsPaused(isPaused);
setRefreshInterval(refreshInterval);
};
return (
<Fragment>
<EuiSpacer />
<EuiSuperDatePicker
isLoading={isLoading}
start={start}
end={end}
onTimeChange={onTimeChange}
onRefresh={onRefresh}
isPaused={isPaused}
refreshInterval={refreshInterval}
onRefreshChange={onRefreshChange}
recentlyUsedRanges={recentlyUsedRanges}
/>
<EuiSpacer />
</Fragment>
);
};

View File

@ -19,6 +19,7 @@
.selectContainer
display: flex
justify-content: space-evenly
align-items: center
margin-bottom: 4%
.select

View File

@ -1,13 +1,12 @@
import React, { useCallback, useEffect, useState } from "react";
import { Backdrop, Box, Button, debounce, Fade, Modal } from "@mui/material";
import { Backdrop, Box, debounce, Fade, Modal } from "@mui/material";
import styles from "./TrafficStatsModal.module.sass";
import closeIcon from "assets/close.svg";
import { TrafficPieChart } from "./TrafficPieChart/TrafficPieChart";
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";
import { TimeRangePicker } from "./TimelineBarChart/TimeRangePicker/TimeTangePicker";
const modalStyle = {
position: 'absolute',
@ -15,7 +14,7 @@ const modalStyle = {
left: '50%',
transform: 'translate(-50%, 0%)',
width: '60vw',
height: '82vh',
height: '90vh',
bgcolor: 'background.paper',
borderRadius: '5px',
boxShadow: 24,
@ -26,11 +25,10 @@ const modalStyle = {
interface TrafficStatsModalProps {
isOpen: boolean;
onClose: () => void;
getTrafficStatsDataApi: () => Promise<any>
getTrafficStatsDataApi: (start?, end?) => Promise<any>
}
export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, onClose, getTrafficStatsDataApi }) => {
const modes = Object.keys(StatsMode).filter(x => !(parseInt(x) >= 0));
const [statsMode, setStatsMode] = useState(modes[0]);
const [selectedProtocol, setSelectedProtocol] = useState(ALL_PROTOCOLS);
@ -38,14 +36,16 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
const [timelineStatsData, setTimelineStatsData] = useState(null);
const [protocols, setProtocols] = useState([])
const [isLoading, setIsLoading] = useState(false);
const commonClasses = useCommonStyles();
const getTrafficStats = useCallback(async () => {
const now = new Date().getTime();
const halfAnHourAgo = new Date().getTime() - (30 * 60 * 1000);
const getTrafficStats = useCallback(async (startTime, endTime) => {
if (isOpen && getTrafficStatsDataApi) {
(async () => {
try {
setIsLoading(true);
const statsData = await getTrafficStatsDataApi();
const statsData = await getTrafficStatsDataApi(startTime, endTime);
setPieStatsData(statsData.pie);
setTimelineStatsData(statsData.timeline);
setProtocols(statsData.protocols)
@ -59,11 +59,11 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
}, [isOpen, getTrafficStatsDataApi, setPieStatsData, setTimelineStatsData])
useEffect(() => {
getTrafficStats();
getTrafficStats(halfAnHourAgo,now);
}, [getTrafficStats])
const refreshStats = debounce(() => {
getTrafficStats();
const refreshStats = debounce((newStartTime, newEndTime) => {
getTrafficStats(newStartTime,newEndTime);
}, 500);
return (
@ -82,18 +82,12 @@ export const TrafficStatsModal: React.FC<TrafficStatsModalProps> = ({ isOpen, on
</div>
<div className={styles.headlineContainer}>
<div className={styles.title}>Traffic Statistics</div>
<Button style={{ marginLeft: "2%", textTransform: 'unset' }}
startIcon={<img src={refreshIcon} className="custom" alt="refresh"></img>}
size="medium"
variant="contained"
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
onClick={refreshStats}
>
Refresh
</Button>
</div>
<div className={styles.mainContainer}>
<div className={styles.selectContainer}>
<div>
<TimeRangePicker refreshStats={refreshStats} />
</div>
<div>
<span style={{ marginRight: 15 }}>Breakdown By</span>
<select className={styles.select} value={statsMode} onChange={(e) => setStatsMode(e.target.value)}>

2280
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@
"private": true,
"dependencies": {
"@craco/craco": "^6.4.3",
"@elastic/datemath": "^5.0.3",
"@elastic/eui": "^60.2.0",
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@mui/material": "^5.8.2",
@ -23,7 +25,6 @@
"mobx": "^6.6.0",
"moment": "^2.29.3",
"node-fetch": "^3.2.4",
"sass": "^1.52.3",
"numeral": "^2.0.6",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.1.0",
@ -35,6 +36,7 @@
"react-syntax-highlighter": "^15.5.0",
"react-toastify": "^8.2.0",
"redoc": "^2.0.0-rc.71",
"sass": "^1.52.3",
"styled-components": "^5.3.5",
"typescript": "^4.7.2",
"web-vitals": "^2.1.4",
@ -49,7 +51,7 @@
"recoil": "^0.7.2"
},
"scripts": {
"prestart": "../devops/ui-common-pack.sh $PWD",
"_prestart": "../devops/ui-common-pack.sh $PWD",
"start": "craco start",
"start-dev": "./node_modules/.bin/env-cmd -f .env.dev.basic craco start",
"build": "./node_modules/.bin/env-cmd -f .env.basic craco build",

View File

@ -9,6 +9,7 @@
name="description"
content="Web site created using create-react-app"
/>
<meta name="eui-style-insert">
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a

View File

@ -10,6 +10,8 @@ import { OasModal } from '@up9/mizu-common';
import Api from './helpers/api';
import {ThemeProvider, StyledEngineProvider, createTheme} from '@mui/material';
import { TrafficStatsModal } from '@up9/mizu-common';
import { EuiProvider } from '@elastic/eui';
import '@elastic/eui/dist/eui_theme_light.css';
const api = Api.getInstance()
@ -20,6 +22,7 @@ const App = () => {
const [trafficStatsModalOpen, setTrafficStatsModalOpen] = useRecoilState(trafficStatsModalOpenAtom);
return (
<EuiProvider>
<StyledEngineProvider injectFirst>
<ThemeProvider theme={createTheme(({}))}>
<div className="mizuApp">
@ -40,6 +43,7 @@ const App = () => {
</div>
</ThemeProvider>
</StyledEngineProvider>
</EuiProvider>
);
}

View File

@ -116,8 +116,8 @@ export default class Api {
});
}
getTrafficStats = async () => {
const response = await client.get("/status/trafficStats");
getTrafficStats = async (startTimeMs, endTimeMs) => {
const response = await client.get("/status/trafficStats", {params: {startTimeMs, endTimeMs}});
return response.data;
}
}