mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-11 16:19:05 +08:00
Merge branch 'main' into issues-106
This commit is contained in:
commit
d6884cacdb
@ -1,3 +1,3 @@
|
||||
export enum LOCAL_STORAGE {
|
||||
METRICS_TIME_IN_DURATION = "metricsTimeDuration",
|
||||
METRICS_TIME_IN_DURATION = "metricsTimeDurations",
|
||||
}
|
||||
|
@ -1,17 +1,11 @@
|
||||
import React, { Suspense } from "react";
|
||||
import { Layout, Spin } from "antd";
|
||||
import { Spin } from "antd";
|
||||
import { useThemeSwitcher } from "react-css-theme-switcher";
|
||||
import ROUTES from "Src/constants/routes";
|
||||
import { IS_LOGGED_IN } from "Src/constants/auth";
|
||||
import {
|
||||
BrowserRouter as Router,
|
||||
Route,
|
||||
Switch,
|
||||
Redirect,
|
||||
} from "react-router-dom";
|
||||
import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
|
||||
|
||||
import SideNav from "./Nav/SideNav";
|
||||
import TopNav from "./Nav/TopNav";
|
||||
import BaseLayout from "./BaseLayout";
|
||||
import {
|
||||
ServiceMetrics,
|
||||
ServiceMap,
|
||||
@ -24,8 +18,6 @@ import {
|
||||
IntstrumentationPage,
|
||||
} from "Src/pages";
|
||||
|
||||
const { Content, Footer } = Layout;
|
||||
|
||||
const App = () => {
|
||||
const { status } = useThemeSwitcher();
|
||||
|
||||
@ -34,47 +26,44 @@ const App = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Router basename="/">
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
<SideNav />
|
||||
<Layout className="site-layout">
|
||||
<Content style={{ margin: "0 16px" }}>
|
||||
<TopNav />
|
||||
<Suspense fallback={<Spin size="large" />}>
|
||||
<Switch>
|
||||
<Route path={ROUTES.SIGN_UP} component={Signup} />
|
||||
<Route path={ROUTES.SERVICE_METRICS} component={ServiceMetrics} />
|
||||
<Route path={ROUTES.SERVICE_MAP} component={ServiceMap} />
|
||||
<Route path={ROUTES.TRACES} exact component={TraceDetail} />
|
||||
<Route path={ROUTES.TRACE_GRAPH} component={TraceGraph} />
|
||||
<Route path={ROUTES.SETTINGS} exact component={SettingsPage} />
|
||||
<Route
|
||||
path={ROUTES.INSTRUMENTATION}
|
||||
exact
|
||||
component={IntstrumentationPage}
|
||||
/>
|
||||
<Route path={ROUTES.USAGE_EXPLORER} component={UsageExplorer} />
|
||||
<Route path={ROUTES.APPLICATION} exact component={ServicesTable} />
|
||||
<Route
|
||||
path="/"
|
||||
exact
|
||||
render={() => {
|
||||
return localStorage.getItem(IS_LOGGED_IN) === "yes" ? (
|
||||
<Redirect to={ROUTES.APPLICATION} />
|
||||
) : (
|
||||
<Redirect to={ROUTES.SIGN_UP} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</Content>
|
||||
<Footer style={{ textAlign: "center", fontSize: 10 }}>
|
||||
SigNoz Inc. ©2020{" "}
|
||||
</Footer>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</Router>
|
||||
<BrowserRouter>
|
||||
<Suspense fallback={<Spin size="large" />}>
|
||||
<Route path={"/"}>
|
||||
<Switch>
|
||||
<BaseLayout>
|
||||
<Route path={ROUTES.SIGN_UP} exact component={Signup} />
|
||||
<Route path={ROUTES.APPLICATION} exact component={ServicesTable} />
|
||||
<Route path={ROUTES.SERVICE_METRICS} exact component={ServiceMetrics} />
|
||||
<Route path={ROUTES.SERVICE_MAP} exact component={ServiceMap} />
|
||||
<Route path={ROUTES.TRACES} exact component={TraceDetail} />
|
||||
<Route path={ROUTES.TRACE_GRAPH} exact component={TraceGraph} />
|
||||
<Route path={ROUTES.SETTINGS} exact component={SettingsPage} />
|
||||
<Route
|
||||
path={ROUTES.INSTRUMENTATION}
|
||||
exact
|
||||
component={IntstrumentationPage}
|
||||
/>
|
||||
<Route
|
||||
path={ROUTES.USAGE_EXPLORER}
|
||||
exactexact
|
||||
component={UsageExplorer}
|
||||
/>
|
||||
<Route
|
||||
path="/"
|
||||
exact
|
||||
render={() => {
|
||||
return localStorage.getItem(IS_LOGGED_IN) === "yes" ? (
|
||||
<Redirect to={ROUTES.APPLICATION} />
|
||||
) : (
|
||||
<Redirect to={ROUTES.SIGN_UP} />
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</BaseLayout>
|
||||
</Switch>
|
||||
</Route>
|
||||
</Suspense>
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
|
||||
|
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,11 +1,12 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { Select as DefaultSelect, Button, Space, Form } from "antd";
|
||||
import styled from "styled-components";
|
||||
import { withRouter } from "react-router";
|
||||
import { getLocalStorageRouteKey } from "./utils";
|
||||
import { RouteComponentProps, useLocation } from "react-router-dom";
|
||||
import { connect } from "react-redux";
|
||||
import ROUTES from "Src/constants/routes";
|
||||
import { findIndex } from "lodash";
|
||||
import CustomDateTimeModal from "./CustomDateTimeModal";
|
||||
import { GlobalTime, updateTimeInterval } from "../../../store/actions";
|
||||
import { StoreState } from "../../../store/reducers";
|
||||
@ -25,9 +26,7 @@ const DateTimeWrapper = styled.div`
|
||||
margin-top: 20px;
|
||||
justify-content: flex-end !important;
|
||||
`;
|
||||
const Select = styled(DefaultSelect)`
|
||||
width: 150px;
|
||||
`;
|
||||
const Select = styled(DefaultSelect)``;
|
||||
interface DateTimeSelectorProps extends RouteComponentProps<any> {
|
||||
currentpath?: string;
|
||||
updateTimeInterval: Function;
|
||||
@ -39,14 +38,23 @@ This components is mounted all the time. Use event listener to track changes.
|
||||
*/
|
||||
const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
||||
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;
|
||||
const defaultTime =
|
||||
location.pathname === ROUTES.SERVICE_MAP ||
|
||||
location.pathname === ROUTES.APPLICATION
|
||||
? DefaultOptionsBasedOnRoute[location.pathname]
|
||||
: DefaultOptionsBasedOnRoute.default;
|
||||
|
||||
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 [timeInterval, setTimeInterval] = useState(defaultTime);
|
||||
const [startTime, setStartTime] = useState<moment.Moment | null>(null);
|
||||
@ -57,9 +65,6 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
||||
const [form_dtselector] = Form.useForm();
|
||||
|
||||
const updateTimeOnQueryParamChange = () => {
|
||||
const timeDurationInLocalStorage = localStorage.getItem(
|
||||
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
||||
);
|
||||
const urlParams = new URLSearchParams(location.search);
|
||||
const intervalInQueryParam = urlParams.get(METRICS_PAGE_QUERY_PARAM.interval);
|
||||
const startTimeString = urlParams.get(METRICS_PAGE_QUERY_PARAM.startTime);
|
||||
@ -75,25 +80,38 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
||||
const startTime = moment(Number(startTimeString));
|
||||
const endTime = moment(Number(endTimeString));
|
||||
setCustomTime(startTime, endTime, true);
|
||||
} else if (currentLocalStorageRouteKey !== LocalStorageRouteKey) {
|
||||
setMetricsTimeInterval(defaultTime);
|
||||
setCurrentLocalStorageRouteKey(LocalStorageRouteKey);
|
||||
}
|
||||
// first pref: handle intervalInQueryParam
|
||||
else if (intervalInQueryParam) {
|
||||
window.localStorage.setItem(
|
||||
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
||||
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
|
||||
useEffect(() => {
|
||||
updateTimeOnQueryParamChange();
|
||||
if (findIndex(options, (option) => option.value === timeInterval) === -1) {
|
||||
setTimeInterval(defaultTime);
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
const setMetricsTimeInterval = (value: string) => {
|
||||
@ -101,8 +119,7 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
||||
setTimeInterval(value);
|
||||
setEndTime(null);
|
||||
setStartTime(null);
|
||||
|
||||
window.localStorage.setItem(LOCAL_STORAGE.METRICS_TIME_IN_DURATION, value);
|
||||
setToLocalStorage(value);
|
||||
};
|
||||
const setCustomTime = (
|
||||
startTime: moment.Moment,
|
||||
@ -259,8 +276,10 @@ const mapStateToProps = (state: StoreState): { globalTime: GlobalTime } => {
|
||||
return { globalTime: state.globalTime };
|
||||
};
|
||||
|
||||
export const DateTimeSelector = connect(mapStateToProps, {
|
||||
updateTimeInterval: updateTimeInterval,
|
||||
})(_DateTimeSelector);
|
||||
export const DateTimeSelector = withRouter(
|
||||
connect(mapStateToProps, {
|
||||
updateTimeInterval: updateTimeInterval,
|
||||
})(_DateTimeSelector),
|
||||
);
|
||||
|
||||
export default withRouter(DateTimeSelector);
|
||||
export default DateTimeSelector;
|
||||
|
@ -19,5 +19,6 @@ export const ServiceMapOptions = [
|
||||
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;
|
||||
};
|
@ -4,6 +4,7 @@ import { InfoCircleOutlined } from "@ant-design/icons";
|
||||
import { Select } from "antd";
|
||||
import styled from "styled-components";
|
||||
const { Option } = Select;
|
||||
import { cloneDeep } from "lodash";
|
||||
|
||||
const Container = styled.div`
|
||||
margin-top: 12px;
|
||||
@ -25,14 +26,25 @@ const Container = styled.div`
|
||||
interface SelectServiceProps {
|
||||
services: servicesItem[];
|
||||
zoomToService: (arg0: string) => void;
|
||||
zoomToDefault: () => void;
|
||||
}
|
||||
|
||||
const defaultOption = {
|
||||
serviceName: "Default"
|
||||
};
|
||||
|
||||
const SelectService = (props: SelectServiceProps) => {
|
||||
const [selectedVal, setSelectedVal] = useState<string>();
|
||||
const { services, zoomToService } = props;
|
||||
const [selectedVal, setSelectedVal] = useState<string>(defaultOption.serviceName);
|
||||
const { zoomToService, zoomToDefault } = props;
|
||||
const services = cloneDeep(props.services);
|
||||
services.unshift(defaultOption)
|
||||
const handleSelect = (value: string) => {
|
||||
if(value === defaultOption.serviceName){
|
||||
zoomToDefault()
|
||||
} else {
|
||||
zoomToService(value);
|
||||
}
|
||||
setSelectedVal(value);
|
||||
zoomToService(value);
|
||||
};
|
||||
return (
|
||||
<Container>
|
||||
|
@ -10,7 +10,8 @@ import {
|
||||
import { Spin } from "antd";
|
||||
import styled from "styled-components";
|
||||
import { StoreState } from "../../store/reducers";
|
||||
import { getGraphData, getTooltip, transformLabel } from "./utils";
|
||||
|
||||
import { getZoomPx, getGraphData, getTooltip, transformLabel } from "./utils";
|
||||
import SelectService from "./SelectService";
|
||||
import { ForceGraph2D } from "react-force-graph";
|
||||
|
||||
@ -72,7 +73,11 @@ const ServiceMap = (props: ServiceMapProps) => {
|
||||
}
|
||||
|
||||
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 zoomToDefault = () => {
|
||||
fgRef && fgRef.current.zoomToFit(100, 120);
|
||||
};
|
||||
|
||||
const { nodes, links } = getGraphData(serviceMap);
|
||||
@ -82,13 +87,11 @@ const ServiceMap = (props: ServiceMapProps) => {
|
||||
<SelectService
|
||||
services={serviceMap.services}
|
||||
zoomToService={zoomToService}
|
||||
zoomToDefault={zoomToDefault}
|
||||
/>
|
||||
<ForceGraph2D
|
||||
ref={fgRef}
|
||||
cooldownTicks={100}
|
||||
onEngineStop={() => {
|
||||
fgRef.current.zoomToFit(100, 120);
|
||||
}}
|
||||
graphData={graphData}
|
||||
nodeLabel={getTooltip}
|
||||
linkAutoColorBy={(d) => d.target}
|
||||
@ -106,7 +109,7 @@ const ServiceMap = (props: ServiceMapProps) => {
|
||||
ctx.fill();
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = "#333333";
|
||||
ctx.fillStyle = "#646464";
|
||||
ctx.fillText(label, node.x, node.y);
|
||||
}}
|
||||
onNodeClick={(node) => {
|
||||
|
@ -74,6 +74,17 @@ export const getGraphData = (serviceMap: serviceMapStore): graphDataType => {
|
||||
};
|
||||
};
|
||||
|
||||
export const getZoomPx = (): number => {
|
||||
const width = window.screen.width;
|
||||
if (width < 1400) {
|
||||
return 190;
|
||||
} else if (width > 1400 && width < 1700) {
|
||||
return 380;
|
||||
} else if (width > 1700) {
|
||||
return 470;
|
||||
}
|
||||
};
|
||||
|
||||
export const getTooltip = (node: {
|
||||
p99: number;
|
||||
errorRate: number;
|
||||
|
@ -38,6 +38,11 @@ export interface servicesAction {
|
||||
|
||||
export const getServiceMapItems = (globalTime: GlobalTime) => {
|
||||
return async (dispatch: Dispatch) => {
|
||||
dispatch<serviceMapItemAction>({
|
||||
type: ActionTypes.getServiceMapItems,
|
||||
payload: [],
|
||||
});
|
||||
|
||||
let request_string =
|
||||
"/serviceMapDependencies?start=" +
|
||||
globalTime.minTime +
|
||||
@ -45,7 +50,7 @@ export const getServiceMapItems = (globalTime: GlobalTime) => {
|
||||
globalTime.maxTime;
|
||||
|
||||
const response = await api.get<servicesMapItem[]>(apiV1 + request_string);
|
||||
|
||||
|
||||
dispatch<serviceMapItemAction>({
|
||||
type: ActionTypes.getServiceMapItems,
|
||||
payload: response.data,
|
||||
@ -55,11 +60,16 @@ export const getServiceMapItems = (globalTime: GlobalTime) => {
|
||||
|
||||
export const getDetailedServiceMapItems = (globalTime: GlobalTime) => {
|
||||
return async (dispatch: Dispatch) => {
|
||||
dispatch<servicesAction>({
|
||||
type: ActionTypes.getServices,
|
||||
payload: [],
|
||||
});
|
||||
|
||||
let request_string =
|
||||
"/services?start=" + globalTime.minTime + "&end=" + globalTime.maxTime;
|
||||
|
||||
const response = await api.get<servicesItem[]>(apiV1 + request_string);
|
||||
|
||||
|
||||
dispatch<servicesAction>({
|
||||
type: ActionTypes.getServices,
|
||||
payload: response.data,
|
||||
|
Loading…
x
Reference in New Issue
Block a user