mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 02:19:02 +08:00
Merge pull request #102 from SigNoz/issue-92
Change time range in api call of Service Map to 1 min from latest
This commit is contained in:
commit
f25edf1e29
@ -1,3 +1,3 @@
|
|||||||
export enum LOCAL_STORAGE {
|
export enum LOCAL_STORAGE {
|
||||||
METRICS_TIME_IN_DURATION = "metricsTimeDuration",
|
METRICS_TIME_IN_DURATION = "metricsTimeDurations",
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
import React, { Suspense } from "react";
|
import React, { Suspense } from "react";
|
||||||
import { Layout, Spin } from "antd";
|
import { Spin } from "antd";
|
||||||
import { useThemeSwitcher } from "react-css-theme-switcher";
|
import { useThemeSwitcher } from "react-css-theme-switcher";
|
||||||
import ROUTES from "Src/constants/routes";
|
import ROUTES from "Src/constants/routes";
|
||||||
import { IS_LOGGED_IN } from "Src/constants/auth";
|
import { IS_LOGGED_IN } from "Src/constants/auth";
|
||||||
import {
|
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
|
||||||
BrowserRouter as Router,
|
|
||||||
Route,
|
|
||||||
Switch,
|
|
||||||
Redirect,
|
|
||||||
} from "react-router-dom";
|
|
||||||
|
|
||||||
import SideNav from "./Nav/SideNav";
|
import BaseLayout from "./BaseLayout";
|
||||||
import TopNav from "./Nav/TopNav";
|
|
||||||
import {
|
import {
|
||||||
ServiceMetrics,
|
ServiceMetrics,
|
||||||
ServiceMap,
|
ServiceMap,
|
||||||
@ -24,8 +18,6 @@ import {
|
|||||||
IntstrumentationPage,
|
IntstrumentationPage,
|
||||||
} from "Src/pages";
|
} from "Src/pages";
|
||||||
|
|
||||||
const { Content, Footer } = Layout;
|
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const { status } = useThemeSwitcher();
|
const { status } = useThemeSwitcher();
|
||||||
|
|
||||||
@ -34,47 +26,44 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router basename="/">
|
<BrowserRouter>
|
||||||
<Layout style={{ minHeight: "100vh" }}>
|
<Suspense fallback={<Spin size="large" />}>
|
||||||
<SideNav />
|
<Route path={"/"}>
|
||||||
<Layout className="site-layout">
|
<Switch>
|
||||||
<Content style={{ margin: "0 16px" }}>
|
<BaseLayout>
|
||||||
<TopNav />
|
<Route path={ROUTES.SIGN_UP} exact component={Signup} />
|
||||||
<Suspense fallback={<Spin size="large" />}>
|
<Route path={ROUTES.APPLICATION} exact component={ServicesTable} />
|
||||||
<Switch>
|
<Route path={ROUTES.SERVICE_METRICS} exact component={ServiceMetrics} />
|
||||||
<Route path={ROUTES.SIGN_UP} component={Signup} />
|
<Route path={ROUTES.SERVICE_MAP} exact component={ServiceMap} />
|
||||||
<Route path={ROUTES.SERVICE_METRICS} component={ServiceMetrics} />
|
<Route path={ROUTES.TRACES} exact component={TraceDetail} />
|
||||||
<Route path={ROUTES.SERVICE_MAP} component={ServiceMap} />
|
<Route path={ROUTES.TRACE_GRAPH} exact component={TraceGraph} />
|
||||||
<Route path={ROUTES.TRACES} exact component={TraceDetail} />
|
<Route path={ROUTES.SETTINGS} exact component={SettingsPage} />
|
||||||
<Route path={ROUTES.TRACE_GRAPH} component={TraceGraph} />
|
<Route
|
||||||
<Route path={ROUTES.SETTINGS} exact component={SettingsPage} />
|
path={ROUTES.INSTRUMENTATION}
|
||||||
<Route
|
exact
|
||||||
path={ROUTES.INSTRUMENTATION}
|
component={IntstrumentationPage}
|
||||||
exact
|
/>
|
||||||
component={IntstrumentationPage}
|
<Route
|
||||||
/>
|
path={ROUTES.USAGE_EXPLORER}
|
||||||
<Route path={ROUTES.USAGE_EXPLORER} component={UsageExplorer} />
|
exactexact
|
||||||
<Route path={ROUTES.APPLICATION} exact component={ServicesTable} />
|
component={UsageExplorer}
|
||||||
<Route
|
/>
|
||||||
path="/"
|
<Route
|
||||||
exact
|
path="/"
|
||||||
render={() => {
|
exact
|
||||||
return localStorage.getItem(IS_LOGGED_IN) === "yes" ? (
|
render={() => {
|
||||||
<Redirect to={ROUTES.APPLICATION} />
|
return localStorage.getItem(IS_LOGGED_IN) === "yes" ? (
|
||||||
) : (
|
<Redirect to={ROUTES.APPLICATION} />
|
||||||
<Redirect to={ROUTES.SIGN_UP} />
|
) : (
|
||||||
);
|
<Redirect to={ROUTES.SIGN_UP} />
|
||||||
}}
|
);
|
||||||
/>
|
}}
|
||||||
</Switch>
|
/>
|
||||||
</Suspense>
|
</BaseLayout>
|
||||||
</Content>
|
</Switch>
|
||||||
<Footer style={{ textAlign: "center", fontSize: 10 }}>
|
</Route>
|
||||||
SigNoz Inc. ©2020{" "}
|
</Suspense>
|
||||||
</Footer>
|
</BrowserRouter>
|
||||||
</Layout>
|
|
||||||
</Layout>
|
|
||||||
</Router>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
29
frontend/src/modules/BaseLayout.tsx
Normal file
29
frontend/src/modules/BaseLayout.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
import { Layout } from "antd";
|
||||||
|
import SideNav from "./Nav/SideNav";
|
||||||
|
import TopNav from "./Nav/TopNav";
|
||||||
|
const { Content, Footer } = Layout;
|
||||||
|
|
||||||
|
interface BaseLayoutProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BaseLayout: React.FC<BaseLayoutProps> = ({ children }) => {
|
||||||
|
return (
|
||||||
|
<Layout style={{ minHeight: "100vh" }}>
|
||||||
|
<SideNav />
|
||||||
|
<Layout className="site-layout">
|
||||||
|
<Content style={{ margin: "0 16px" }}>
|
||||||
|
<TopNav />
|
||||||
|
{children}
|
||||||
|
</Content>
|
||||||
|
<Footer style={{ textAlign: "center", fontSize: 10 }}>
|
||||||
|
SigNoz Inc. ©2020{" "}
|
||||||
|
</Footer>
|
||||||
|
</Layout>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BaseLayout;
|
@ -1,27 +1,32 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Select, Button, Space, Form } from "antd";
|
import { cloneDeep } from "lodash";
|
||||||
|
import { Select as DefaultSelect, Button, Space, Form } from "antd";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { withRouter } from "react-router";
|
import { withRouter } from "react-router";
|
||||||
|
import { getLocalStorageRouteKey } from "./utils";
|
||||||
import { RouteComponentProps, useLocation } from "react-router-dom";
|
import { RouteComponentProps, useLocation } from "react-router-dom";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import ROUTES from "Src/constants/routes";
|
import ROUTES from "Src/constants/routes";
|
||||||
|
|
||||||
import CustomDateTimeModal from "./CustomDateTimeModal";
|
import CustomDateTimeModal from "./CustomDateTimeModal";
|
||||||
import { GlobalTime, updateTimeInterval } from "../../../store/actions";
|
import { GlobalTime, updateTimeInterval } from "../../../store/actions";
|
||||||
import { StoreState } from "../../../store/reducers";
|
import { StoreState } from "../../../store/reducers";
|
||||||
import FormItem from "antd/lib/form/FormItem";
|
import FormItem from "antd/lib/form/FormItem";
|
||||||
|
import {
|
||||||
|
Options,
|
||||||
|
ServiceMapOptions,
|
||||||
|
DefaultOptionsBasedOnRoute,
|
||||||
|
} from "./config";
|
||||||
import { DateTimeRangeType } from "../../../store/actions";
|
import { DateTimeRangeType } from "../../../store/actions";
|
||||||
import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query";
|
import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query";
|
||||||
import { LOCAL_STORAGE } from "Src/constants/localStorage";
|
import { LOCAL_STORAGE } from "Src/constants/localStorage";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
const { Option } = Select;
|
const { Option } = DefaultSelect;
|
||||||
|
|
||||||
const DateTimeWrapper = styled.div`
|
const DateTimeWrapper = styled.div`
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
justify-content: flex-end !important;
|
justify-content: flex-end !important;
|
||||||
`;
|
`;
|
||||||
|
const Select = styled(DefaultSelect)``;
|
||||||
interface DateTimeSelectorProps extends RouteComponentProps<any> {
|
interface DateTimeSelectorProps extends RouteComponentProps<any> {
|
||||||
currentpath?: string;
|
currentpath?: string;
|
||||||
updateTimeInterval: Function;
|
updateTimeInterval: Function;
|
||||||
@ -32,21 +37,34 @@ interface DateTimeSelectorProps extends RouteComponentProps<any> {
|
|||||||
This components is mounted all the time. Use event listener to track changes.
|
This components is mounted all the time. Use event listener to track changes.
|
||||||
*/
|
*/
|
||||||
const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
||||||
const defaultTime = "30min";
|
const location = useLocation();
|
||||||
|
const LocalStorageRouteKey: string = getLocalStorageRouteKey(
|
||||||
|
location.pathname,
|
||||||
|
);
|
||||||
|
const timeDurationInLocalStorage =
|
||||||
|
JSON.parse(localStorage.getItem(LOCAL_STORAGE.METRICS_TIME_IN_DURATION)) ||
|
||||||
|
{};
|
||||||
|
const options =
|
||||||
|
location.pathname === ROUTES.SERVICE_MAP ? ServiceMapOptions : Options;
|
||||||
|
let defaultTime = DefaultOptionsBasedOnRoute[LocalStorageRouteKey]
|
||||||
|
? DefaultOptionsBasedOnRoute[LocalStorageRouteKey]
|
||||||
|
: DefaultOptionsBasedOnRoute.default;
|
||||||
|
if (timeDurationInLocalStorage[LocalStorageRouteKey]) {
|
||||||
|
defaultTime = timeDurationInLocalStorage[LocalStorageRouteKey];
|
||||||
|
}
|
||||||
|
const [currentLocalStorageRouteKey, setCurrentLocalStorageRouteKey] = useState(
|
||||||
|
LocalStorageRouteKey,
|
||||||
|
);
|
||||||
const [customDTPickerVisible, setCustomDTPickerVisible] = useState(false);
|
const [customDTPickerVisible, setCustomDTPickerVisible] = useState(false);
|
||||||
const [timeInterval, setTimeInterval] = useState(defaultTime);
|
const [timeInterval, setTimeInterval] = useState(defaultTime);
|
||||||
const [startTime, setStartTime] = useState<moment.Moment | null>(null);
|
const [startTime, setStartTime] = useState<moment.Moment | null>(null);
|
||||||
const [endTime, setEndTime] = useState<moment.Moment | null>(null);
|
const [endTime, setEndTime] = useState<moment.Moment | null>(null);
|
||||||
const [refreshButtonHidden, setRefreshButtonHidden] = useState(false);
|
const [refreshButtonHidden, setRefreshButtonHidden] = useState(false);
|
||||||
const [refreshText, setRefreshText] = useState("");
|
const [refreshText, setRefreshText] = useState("");
|
||||||
const [refreshButtonClick, setRefreshButtoClick] = useState(0);
|
const [refreshButtonClick, setRefreshButtonClick] = useState(0);
|
||||||
const [form_dtselector] = Form.useForm();
|
const [form_dtselector] = Form.useForm();
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
const updateTimeOnQueryParamChange = () => {
|
const updateTimeOnQueryParamChange = () => {
|
||||||
const timeDurationInLocalStorage = localStorage.getItem(
|
|
||||||
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
|
||||||
);
|
|
||||||
const urlParams = new URLSearchParams(location.search);
|
const urlParams = new URLSearchParams(location.search);
|
||||||
const intervalInQueryParam = urlParams.get(METRICS_PAGE_QUERY_PARAM.interval);
|
const intervalInQueryParam = urlParams.get(METRICS_PAGE_QUERY_PARAM.interval);
|
||||||
const startTimeString = urlParams.get(METRICS_PAGE_QUERY_PARAM.startTime);
|
const startTimeString = urlParams.get(METRICS_PAGE_QUERY_PARAM.startTime);
|
||||||
@ -62,36 +80,46 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
const startTime = moment(Number(startTimeString));
|
const startTime = moment(Number(startTimeString));
|
||||||
const endTime = moment(Number(endTimeString));
|
const endTime = moment(Number(endTimeString));
|
||||||
setCustomTime(startTime, endTime, true);
|
setCustomTime(startTime, endTime, true);
|
||||||
|
} else if (currentLocalStorageRouteKey !== LocalStorageRouteKey) {
|
||||||
|
setMetricsTimeInterval(defaultTime);
|
||||||
|
setCurrentLocalStorageRouteKey(LocalStorageRouteKey);
|
||||||
}
|
}
|
||||||
// first pref: handle intervalInQueryParam
|
// first pref: handle intervalInQueryParam
|
||||||
else if (intervalInQueryParam) {
|
else if (intervalInQueryParam) {
|
||||||
window.localStorage.setItem(
|
|
||||||
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
|
||||||
intervalInQueryParam,
|
|
||||||
);
|
|
||||||
setMetricsTimeInterval(intervalInQueryParam);
|
setMetricsTimeInterval(intervalInQueryParam);
|
||||||
} else if (timeDurationInLocalStorage) {
|
|
||||||
setMetricsTimeInterval(timeDurationInLocalStorage);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setToLocalStorage = (val: string) => {
|
||||||
|
let timeDurationInLocalStorageObj = cloneDeep(timeDurationInLocalStorage);
|
||||||
|
if (timeDurationInLocalStorageObj) {
|
||||||
|
timeDurationInLocalStorageObj[LocalStorageRouteKey] = val;
|
||||||
|
} else {
|
||||||
|
timeDurationInLocalStorageObj = {
|
||||||
|
[LocalStorageRouteKey]: val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
window.localStorage.setItem(
|
||||||
|
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
||||||
|
JSON.stringify(timeDurationInLocalStorageObj),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMetricsTimeInterval(defaultTime);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// On URL Change
|
// On URL Change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateTimeOnQueryParamChange();
|
updateTimeOnQueryParamChange();
|
||||||
}, [location]);
|
}, [location]);
|
||||||
|
|
||||||
//On mount
|
|
||||||
useEffect(() => {
|
|
||||||
updateTimeOnQueryParamChange();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const setMetricsTimeInterval = (value: string) => {
|
const setMetricsTimeInterval = (value: string) => {
|
||||||
props.updateTimeInterval(value);
|
props.updateTimeInterval(value);
|
||||||
setTimeInterval(value);
|
setTimeInterval(value);
|
||||||
setEndTime(null);
|
setEndTime(null);
|
||||||
setStartTime(null);
|
setStartTime(null);
|
||||||
|
setToLocalStorage(value);
|
||||||
window.localStorage.setItem(LOCAL_STORAGE.METRICS_TIME_IN_DURATION, value);
|
|
||||||
};
|
};
|
||||||
const setCustomTime = (
|
const setCustomTime = (
|
||||||
startTime: moment.Moment,
|
startTime: moment.Moment,
|
||||||
@ -173,7 +201,7 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
setRefreshButtoClick(refreshButtonClick + 1);
|
setRefreshButtonClick(refreshButtonClick + 1);
|
||||||
setMetricsTimeInterval(timeInterval);
|
setMetricsTimeInterval(timeInterval);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -187,15 +215,6 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
};
|
};
|
||||||
}, [props.location, refreshButtonClick]);
|
}, [props.location, refreshButtonClick]);
|
||||||
|
|
||||||
const options = [
|
|
||||||
{ value: "custom", label: "Custom" },
|
|
||||||
{ value: "15min", label: "Last 15 min" },
|
|
||||||
{ value: "30min", label: "Last 30 min" },
|
|
||||||
{ value: "1hr", label: "Last 1 hour" },
|
|
||||||
{ value: "6hr", label: "Last 6 hour" },
|
|
||||||
{ value: "1day", label: "Last 1 day" },
|
|
||||||
{ value: "1week", label: "Last 1 week" },
|
|
||||||
];
|
|
||||||
if (props.location.pathname.startsWith(ROUTES.USAGE_EXPLORER)) {
|
if (props.location.pathname.startsWith(ROUTES.USAGE_EXPLORER)) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
@ -205,6 +224,7 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
"YYYY/MM/DD HH:mm",
|
"YYYY/MM/DD HH:mm",
|
||||||
)}`
|
)}`
|
||||||
: timeInterval;
|
: timeInterval;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DateTimeWrapper>
|
<DateTimeWrapper>
|
||||||
<Space style={{ float: "right", display: "block" }}>
|
<Space style={{ float: "right", display: "block" }}>
|
||||||
@ -256,8 +276,10 @@ const mapStateToProps = (state: StoreState): { globalTime: GlobalTime } => {
|
|||||||
return { globalTime: state.globalTime };
|
return { globalTime: state.globalTime };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DateTimeSelector = connect(mapStateToProps, {
|
export const DateTimeSelector = withRouter(
|
||||||
updateTimeInterval: updateTimeInterval,
|
connect(mapStateToProps, {
|
||||||
})(_DateTimeSelector);
|
updateTimeInterval: updateTimeInterval,
|
||||||
|
})(_DateTimeSelector),
|
||||||
|
);
|
||||||
|
|
||||||
export default withRouter(DateTimeSelector);
|
export default DateTimeSelector;
|
||||||
|
24
frontend/src/modules/Nav/TopNav/config.ts
Normal file
24
frontend/src/modules/Nav/TopNav/config.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import ROUTES from "Src/constants/routes";
|
||||||
|
|
||||||
|
export const Options = [
|
||||||
|
{ value: "5min", label: "Last 5 min" },
|
||||||
|
{ value: "15min", label: "Last 15 min" },
|
||||||
|
{ value: "30min", label: "Last 30 min" },
|
||||||
|
{ value: "1hr", label: "Last 1 hour" },
|
||||||
|
{ value: "6hr", label: "Last 6 hour" },
|
||||||
|
{ value: "1day", label: "Last 1 day" },
|
||||||
|
{ value: "1week", label: "Last 1 week" },
|
||||||
|
{ value: "custom", label: "Custom" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ServiceMapOptions = [
|
||||||
|
{ value: "1min", label: "Last 1 min" },
|
||||||
|
{ value: "5min", label: "Last 5 min" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const DefaultOptionsBasedOnRoute = {
|
||||||
|
[ROUTES.SERVICE_MAP]: ServiceMapOptions[0].value,
|
||||||
|
[ROUTES.APPLICATION]: Options[0].value,
|
||||||
|
[ROUTES.SERVICE_METRICS]: Options[2].value,
|
||||||
|
default: Options[2].value,
|
||||||
|
};
|
18
frontend/src/modules/Nav/TopNav/utils.ts
Normal file
18
frontend/src/modules/Nav/TopNav/utils.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import ROUTES from "Src/constants/routes";
|
||||||
|
|
||||||
|
export const getLocalStorageRouteKey = (pathName: string) => {
|
||||||
|
let localStorageKey = "";
|
||||||
|
const pathNameSplit = pathName.split("/");
|
||||||
|
if (!pathNameSplit[2]) {
|
||||||
|
localStorageKey = pathName;
|
||||||
|
} else {
|
||||||
|
Object.keys(ROUTES).forEach((key) => {
|
||||||
|
if (ROUTES[key].indexOf(":") > -1) {
|
||||||
|
if (ROUTES[key].indexOf(pathNameSplit[1]) > -1) {
|
||||||
|
localStorageKey = ROUTES[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return localStorageKey;
|
||||||
|
};
|
@ -10,7 +10,7 @@ import {
|
|||||||
import { Spin } from "antd";
|
import { Spin } from "antd";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { StoreState } from "../../store/reducers";
|
import { StoreState } from "../../store/reducers";
|
||||||
import { getGraphData } from "./utils";
|
import { getZoomPx, getGraphData, getTooltip } from "./utils";
|
||||||
import SelectService from "./SelectService";
|
import SelectService from "./SelectService";
|
||||||
import { ForceGraph2D } from "react-force-graph";
|
import { ForceGraph2D } from "react-force-graph";
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ const ServiceMap = (props: ServiceMapProps) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getServiceMapItems(globalTime);
|
getServiceMapItems(globalTime);
|
||||||
getDetailedServiceMapItems(globalTime);
|
getDetailedServiceMapItems(globalTime);
|
||||||
}, []);
|
}, [globalTime]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fgRef.current && fgRef.current.d3Force("charge").strength(-400);
|
fgRef.current && fgRef.current.d3Force("charge").strength(-400);
|
||||||
@ -72,7 +72,7 @@ const ServiceMap = (props: ServiceMapProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const zoomToService = (value: string) => {
|
const zoomToService = (value: string) => {
|
||||||
fgRef && fgRef.current.zoomToFit(700, 380, (e) => e.id === value);
|
fgRef && fgRef.current.zoomToFit(700, getZoomPx(), (e) => e.id === value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { nodes, links } = getGraphData(serviceMap);
|
const { nodes, links } = getGraphData(serviceMap);
|
||||||
@ -90,7 +90,7 @@ const ServiceMap = (props: ServiceMapProps) => {
|
|||||||
fgRef.current.zoomToFit(100, 120);
|
fgRef.current.zoomToFit(100, 120);
|
||||||
}}
|
}}
|
||||||
graphData={graphData}
|
graphData={graphData}
|
||||||
nodeLabel="id"
|
nodeLabel={getTooltip}
|
||||||
linkAutoColorBy={(d) => d.target}
|
linkAutoColorBy={(d) => d.target}
|
||||||
linkDirectionalParticles="value"
|
linkDirectionalParticles="value"
|
||||||
linkDirectionalParticleSpeed={(d) => d.value}
|
linkDirectionalParticleSpeed={(d) => d.value}
|
||||||
@ -112,21 +112,7 @@ const ServiceMap = (props: ServiceMapProps) => {
|
|||||||
onNodeClick={(node) => {
|
onNodeClick={(node) => {
|
||||||
const tooltip = document.querySelector(".graph-tooltip");
|
const tooltip = document.querySelector(".graph-tooltip");
|
||||||
if (tooltip && node) {
|
if (tooltip && node) {
|
||||||
tooltip.innerHTML = `<div style="color:#333333;padding:12px;background: white;border-radius: 2px;">
|
tooltip.innerHTML = getTooltip(node);
|
||||||
<div style="font-weight:bold; margin-bottom:16px;">${node.id}</div>
|
|
||||||
<div class="keyval">
|
|
||||||
<div class="key">P99 latency:</div>
|
|
||||||
<div class="val">${node.p99 / 1000000}ms</div>
|
|
||||||
</div>
|
|
||||||
<div class="keyval">
|
|
||||||
<div class="key">Request:</div>
|
|
||||||
<div class="val">${node.callRate}/sec</div>
|
|
||||||
</div>
|
|
||||||
<div class="keyval">
|
|
||||||
<div class="key">Error Rate:</div>
|
|
||||||
<div class="val">${node.errorRate}%</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
nodePointerAreaPaint={(node, color, ctx) => {
|
nodePointerAreaPaint={(node, color, ctx) => {
|
||||||
|
@ -73,3 +73,37 @@ export const getGraphData = (serviceMap: serviceMapStore): graphDataType => {
|
|||||||
links,
|
links,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getZoomPx = (): number => {
|
||||||
|
const width = window.screen.width;
|
||||||
|
if (width < 1400) {
|
||||||
|
return 190;
|
||||||
|
} else if (width > 1400 && width < 2500) {
|
||||||
|
return 380;
|
||||||
|
} else if (width > 2500) {
|
||||||
|
return 360;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTooltip = (node: {
|
||||||
|
p99: number;
|
||||||
|
errorRate: number;
|
||||||
|
callRate: number;
|
||||||
|
id: string;
|
||||||
|
}) => {
|
||||||
|
return `<div style="color:#333333;padding:12px;background: white;border-radius: 2px;">
|
||||||
|
<div style="font-weight:bold; margin-bottom:16px;">${node.id}</div>
|
||||||
|
<div class="keyval">
|
||||||
|
<div class="key">P99 latency:</div>
|
||||||
|
<div class="val">${node.p99 / 1000000}ms</div>
|
||||||
|
</div>
|
||||||
|
<div class="keyval">
|
||||||
|
<div class="key">Request:</div>
|
||||||
|
<div class="val">${node.callRate}/sec</div>
|
||||||
|
</div>
|
||||||
|
<div class="keyval">
|
||||||
|
<div class="key">Error Rate:</div>
|
||||||
|
<div class="val">${node.errorRate}%</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
};
|
||||||
|
@ -23,6 +23,15 @@ export const updateTimeInterval = (
|
|||||||
// set directly based on that. Assuming datetimeRange values are in ms, and minTime is 0th element
|
// set directly based on that. Assuming datetimeRange values are in ms, and minTime is 0th element
|
||||||
|
|
||||||
switch (interval) {
|
switch (interval) {
|
||||||
|
case "1min":
|
||||||
|
maxTime = Date.now() * 1000000; // in nano sec
|
||||||
|
minTime = (Date.now() - 1 * 60 * 1000) * 1000000;
|
||||||
|
break;
|
||||||
|
case "5min":
|
||||||
|
maxTime = Date.now() * 1000000; // in nano sec
|
||||||
|
minTime = (Date.now() - 5 * 60 * 1000) * 1000000;
|
||||||
|
break;
|
||||||
|
|
||||||
case "15min":
|
case "15min":
|
||||||
maxTime = Date.now() * 1000000; // in nano sec
|
maxTime = Date.now() * 1000000; // in nano sec
|
||||||
minTime = (Date.now() - 15 * 60 * 1000) * 1000000;
|
minTime = (Date.now() - 15 * 60 * 1000) * 1000000;
|
||||||
|
@ -38,6 +38,11 @@ export interface servicesAction {
|
|||||||
|
|
||||||
export const getServiceMapItems = (globalTime: GlobalTime) => {
|
export const getServiceMapItems = (globalTime: GlobalTime) => {
|
||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch) => {
|
||||||
|
dispatch<serviceMapItemAction>({
|
||||||
|
type: ActionTypes.getServiceMapItems,
|
||||||
|
payload: [],
|
||||||
|
});
|
||||||
|
|
||||||
let request_string =
|
let request_string =
|
||||||
"/serviceMapDependencies?start=" +
|
"/serviceMapDependencies?start=" +
|
||||||
globalTime.minTime +
|
globalTime.minTime +
|
||||||
@ -45,7 +50,7 @@ export const getServiceMapItems = (globalTime: GlobalTime) => {
|
|||||||
globalTime.maxTime;
|
globalTime.maxTime;
|
||||||
|
|
||||||
const response = await api.get<servicesMapItem[]>(apiV1 + request_string);
|
const response = await api.get<servicesMapItem[]>(apiV1 + request_string);
|
||||||
|
|
||||||
dispatch<serviceMapItemAction>({
|
dispatch<serviceMapItemAction>({
|
||||||
type: ActionTypes.getServiceMapItems,
|
type: ActionTypes.getServiceMapItems,
|
||||||
payload: response.data,
|
payload: response.data,
|
||||||
@ -55,11 +60,16 @@ export const getServiceMapItems = (globalTime: GlobalTime) => {
|
|||||||
|
|
||||||
export const getDetailedServiceMapItems = (globalTime: GlobalTime) => {
|
export const getDetailedServiceMapItems = (globalTime: GlobalTime) => {
|
||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch) => {
|
||||||
|
dispatch<servicesAction>({
|
||||||
|
type: ActionTypes.getServices,
|
||||||
|
payload: [],
|
||||||
|
});
|
||||||
|
|
||||||
let request_string =
|
let request_string =
|
||||||
"/services?start=" + globalTime.minTime + "&end=" + globalTime.maxTime;
|
"/services?start=" + globalTime.minTime + "&end=" + globalTime.maxTime;
|
||||||
|
|
||||||
const response = await api.get<servicesItem[]>(apiV1 + request_string);
|
const response = await api.get<servicesItem[]>(apiV1 + request_string);
|
||||||
|
|
||||||
dispatch<servicesAction>({
|
dispatch<servicesAction>({
|
||||||
type: ActionTypes.getServices,
|
type: ActionTypes.getServices,
|
||||||
payload: response.data,
|
payload: response.data,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user