diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..8a22860f1c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +## Bug description + +*Please describe.* +*If this affects the front-end, screenshots would be of great help.* + +## Expected behavior + + + +## How to reproduce + +1. +2. +3. + + + +## Additional context + + +#### *Thank you* for your bug report – we love squashing them! diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..b8871ec018 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,29 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +## Is your feature request related to a problem? + +*Please describe.* + +## Describe the solution you'd like + + + +## Describe alternatives you've considered + + + +## Additional context + + + +#### *Thank you* for your feature request – we love each and every one! + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/performance-issue-report.md b/.github/ISSUE_TEMPLATE/performance-issue-report.md new file mode 100644 index 0000000000..c038877ca1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/performance-issue-report.md @@ -0,0 +1,33 @@ +--- +name: Performance issue report +about: Long response times, high resource usage? Ensuring that SigNoz is scalable + is our top priority +title: '' +labels: '' +assignees: '' + +--- + +## In what situation are you experiencing subpar performance? + +*Please describe.* + +## How to reproduce + +1. +2. +3. + +## Your Environment + +- [ ] Linux +- [ ] Mac +- [ ] Windows + +Please provide details of OS version etc. + +## Additional context + + + +#### *Thank you* for your performance issue report – we want SigNoz to be blazing fast! diff --git a/README.md b/README.md index 9f9b7234d3..99ef8c3c61 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ License Downloads GitHub issues - + tweet

diff --git a/frontend/src/modules/AppWrapper.tsx b/frontend/src/modules/AppWrapper.tsx index b261ad3e32..11e53cd04d 100644 --- a/frontend/src/modules/AppWrapper.tsx +++ b/frontend/src/modules/AppWrapper.tsx @@ -17,6 +17,7 @@ import { SettingsPage, IntstrumentationPage, } from "Src/pages"; +import { RouteProvider } from "./RouteProvider"; const App = () => { const { status } = useThemeSwitcher(); @@ -30,36 +31,38 @@ const App = () => { }> - - - - - - - - - - - { - return localStorage.getItem(IS_LOGGED_IN) === "yes" ? ( - - ) : ( - - ); - }} - /> - + + + + + + + + + + + + { + return localStorage.getItem(IS_LOGGED_IN) === "yes" ? ( + + ) : ( + + ); + }} + /> + + diff --git a/frontend/src/modules/BaseLayout.tsx b/frontend/src/modules/BaseLayout.tsx index a36ac96e66..6e3f52769e 100644 --- a/frontend/src/modules/BaseLayout.tsx +++ b/frontend/src/modules/BaseLayout.tsx @@ -1,8 +1,12 @@ -import React, { ReactNode } from "react"; +import React, { ReactNode, useEffect } from "react"; import { Layout } from "antd"; import SideNav from "./Nav/SideNav"; import TopNav from "./Nav/TopNav"; +import { useLocation } from "react-router-dom"; +import ROUTES from "Src/constants/routes"; +import { useRoute } from "./RouteProvider"; + const { Content, Footer } = Layout; interface BaseLayoutProps { @@ -10,6 +14,13 @@ interface BaseLayoutProps { } const BaseLayout: React.FC = ({ children }) => { + const location = useLocation(); + const { dispatch } = useRoute(); + + useEffect(() => { + dispatch({ type: "UPDATE_IS_LOADED", payload: location.pathname }); + }, [location]); + return ( diff --git a/frontend/src/modules/Metrics/TopEndpointsTable.css b/frontend/src/modules/Metrics/TopEndpointsTable.css new file mode 100644 index 0000000000..526a2f8349 --- /dev/null +++ b/frontend/src/modules/Metrics/TopEndpointsTable.css @@ -0,0 +1,12 @@ +@media only screen and (min-width: 768px) { + .topEndpointsButton { + white-space: nowrap; + padding: 0; + } + + .topEndpointsButton span { + text-overflow: ellipsis; + overflow: hidden; + max-width: 120px; + } +} diff --git a/frontend/src/modules/Metrics/TopEndpointsTable.tsx b/frontend/src/modules/Metrics/TopEndpointsTable.tsx index b4584981cd..6ab2022574 100644 --- a/frontend/src/modules/Metrics/TopEndpointsTable.tsx +++ b/frontend/src/modules/Metrics/TopEndpointsTable.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Table, Button } from "antd"; +import { Table, Button, Tooltip } from "antd"; import { connect } from "react-redux"; import styled from "styled-components"; import { useHistory, useParams } from "react-router-dom"; @@ -7,12 +7,16 @@ import { topEndpointListItem } from "../../store/actions/metrics"; import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query"; import { GlobalTime } from "Src/store/actions"; import { StoreState } from "Src/store/reducers"; +import "./TopEndpointsTable.css"; const Wrapper = styled.div` padding-top: 10px; padding-bottom: 10px; - padding-left: 20px; - padding-right: 20px; + padding-left: 8px; + padding-right: 8px; + @media only screen and (max-width: 767px) { + padding: 0; + } .ant-table table { font-size: 12px; } @@ -22,6 +26,9 @@ const Wrapper = styled.div` .ant-table-thead > tr > th { padding: 10px; } + .ant-table-column-sorters { + padding: 6px; + } `; interface TopEndpointsTableProps { @@ -58,9 +65,15 @@ const _TopEndpointsTable = (props: TopEndpointsTableProps) => { key: "name", render: (text: string) => ( - + + + ), }, { diff --git a/frontend/src/modules/RouteProvider.tsx b/frontend/src/modules/RouteProvider.tsx new file mode 100644 index 0000000000..0680e912c8 --- /dev/null +++ b/frontend/src/modules/RouteProvider.tsx @@ -0,0 +1,83 @@ +import React, { useContext, createContext, ReactNode, Dispatch } from "react"; +import ROUTES from "Src/constants/routes"; + +type State = { + [key: string]: { + route: string; + isLoaded: boolean; + }; +}; + +enum ActionTypes { + UPDATE_IS_LOADED = "UPDATE_IS_LOADED", +} + +type Action = { + type: ActionTypes; + payload: string; +}; + +interface ContextType { + state: State; + dispatch: Dispatch; +} + +const RouteContext = createContext(null); + +interface RouteProviderProps { + children: ReactNode; +} +interface RouteObj { + [key: string]: { + route: string; + isLoaded: boolean; + }; +} + +const updateLocation = (state: State, action: Action): State => { + if (action.type === ActionTypes.UPDATE_IS_LOADED) { + /* + Update the isLoaded property in routes obj + if the route matches the current pathname + + Why: Checkout this issue https://github.com/SigNoz/signoz/issues/110 + To avoid calling the api's twice for Date picker, + We will only call once the route is changed + */ + Object.keys(ROUTES).map((items) => { + state[items].isLoaded = state[items].route === action.payload; + }); + return { + ...state, + }; + } + return { + ...state, + }; +}; + +const getInitialState = () => { + const routes: RouteObj = {}; + Object.keys(ROUTES).map((items) => { + routes[items] = { + route: `${ROUTES[items]}`, + isLoaded: false, + }; + }); + return routes; +}; + +const RouteProvider: React.FC = ({ children }) => { + const [state, dispatch] = React.useReducer(updateLocation, getInitialState()); + const value = { state, dispatch }; + return {children}; +}; + +const useRoute = (): ContextType => { + const context = useContext(RouteContext); + if (context === undefined) { + throw new Error("useRoute must be used within a RouteProvider"); + } + return context as ContextType; +}; +export { RouteProvider, useRoute }; diff --git a/frontend/src/modules/Servicemap/ServiceMap.tsx b/frontend/src/modules/Servicemap/ServiceMap.tsx index 048c6980b9..fe31b8d8fb 100644 --- a/frontend/src/modules/Servicemap/ServiceMap.tsx +++ b/frontend/src/modules/Servicemap/ServiceMap.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useContext, useEffect, useRef } from "react"; import { connect } from "react-redux"; import { RouteComponentProps } from "react-router-dom"; import { @@ -14,6 +14,7 @@ import { StoreState } from "../../store/reducers"; import { getZoomPx, getGraphData, getTooltip, transformLabel } from "./utils"; import SelectService from "./SelectService"; import { ForceGraph2D } from "react-force-graph"; +import { useRoute } from "../RouteProvider"; const Container = styled.div` .force-graph-container .graph-tooltip { @@ -53,6 +54,8 @@ export interface graphDataType { const ServiceMap = (props: ServiceMapProps) => { const fgRef = useRef(); + const { state } = useRoute(); + const { getDetailedServiceMapItems, getServiceMapItems, @@ -61,8 +64,14 @@ const ServiceMap = (props: ServiceMapProps) => { } = props; useEffect(() => { - getServiceMapItems(globalTime); - getDetailedServiceMapItems(globalTime); + /* + Call the apis only when the route is loaded. + Check this issue: https://github.com/SigNoz/signoz/issues/110 + */ + if (state.SERVICE_MAP.isLoaded) { + getServiceMapItems(globalTime); + getDetailedServiceMapItems(globalTime); + } }, [globalTime]); useEffect(() => { diff --git a/frontend/src/modules/Traces/TraceCustomVisualizations.tsx b/frontend/src/modules/Traces/TraceCustomVisualizations.tsx index 3c81ad244b..baf3271c64 100644 --- a/frontend/src/modules/Traces/TraceCustomVisualizations.tsx +++ b/frontend/src/modules/Traces/TraceCustomVisualizations.tsx @@ -10,6 +10,7 @@ import { GlobalTime, TraceFilters, } from "../../store/actions"; +import { useRoute } from "../RouteProvider"; const { Option } = Select; @@ -81,6 +82,8 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => { const [selectedEntity, setSelectedEntity] = useState("calls"); const [selectedAggOption, setSelectedAggOption] = useState("count"); const [selectedStep, setSelectedStep] = useState("60"); + const { state } = useRoute(); + // Step should be multiples of 60, 60 -> 1 min useEffect(() => { @@ -109,7 +112,14 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => { minTime: props.globalTime.minTime - 15 * 60 * 1000000000, maxTime: props.globalTime.maxTime + 15 * 60 * 1000000000, }; - props.getFilteredTraceMetrics(request_string, plusMinus15); + + /* + Call the apis only when the route is loaded. + Check this issue: https://github.com/SigNoz/signoz/issues/110 + */ + if (state.TRACES.isLoaded) { + props.getFilteredTraceMetrics(request_string, plusMinus15); + } }, [selectedEntity, selectedAggOption, props.traceFilters, props.globalTime]); //Custom metrics API called if time, tracefilters, selected entity or agg option changes diff --git a/frontend/src/modules/Traces/TraceFilter.tsx b/frontend/src/modules/Traces/TraceFilter.tsx index 839ef64d12..82d679895d 100644 --- a/frontend/src/modules/Traces/TraceFilter.tsx +++ b/frontend/src/modules/Traces/TraceFilter.tsx @@ -18,6 +18,7 @@ import FormItem from "antd/lib/form/FormItem"; import api, { apiV1 } from "../../api"; import { useLocation } from "react-router-dom"; import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query"; +import { useRoute } from "../RouteProvider"; const { Option } = Select; @@ -45,6 +46,7 @@ const _TraceFilter = (props: TraceFilterProps) => { const [tagKeyOptions, setTagKeyOptions] = useState([]); const location = useLocation(); const urlParams = new URLSearchParams(location.search.split("?")[1]); + const { state } = useRoute(); useEffect(() => { handleApplyFilterForm({ @@ -122,7 +124,13 @@ const _TraceFilter = (props: TraceFilterProps) => { "&tags=" + encodeURIComponent(JSON.stringify(props.traceFilters.tags)); - props.fetchTraces(props.globalTime, request_string); + /* + Call the apis only when the route is loaded. + Check this issue: https://github.com/SigNoz/signoz/issues/110 + */ + if (state.TRACES.isLoaded) { + props.fetchTraces(props.globalTime, request_string); + } }, [props.traceFilters, props.globalTime]); useEffect(() => { diff --git a/frontend/src/modules/Usage/UsageExplorer.tsx b/frontend/src/modules/Usage/UsageExplorer.tsx index 3152e12693..d02cc8eebb 100644 --- a/frontend/src/modules/Usage/UsageExplorer.tsx +++ b/frontend/src/modules/Usage/UsageExplorer.tsx @@ -13,6 +13,7 @@ import { import { StoreState } from "../../store/reducers"; import moment from "moment"; import { isOnboardingSkipped } from "../../utils/app"; +import { useRoute } from "../RouteProvider"; const { Option } = Select; interface UsageExplorerProps { @@ -56,6 +57,8 @@ const _UsageExplorer = (props: UsageExplorerProps) => { const [selectedInterval, setSelectedInterval] = useState(interval[2]); const [selectedService, setSelectedService] = useState(""); + const { state } = useRoute(); + useEffect(() => { if (selectedTime && selectedInterval) { const maxTime = new Date().getTime() * 1000000; @@ -71,7 +74,13 @@ const _UsageExplorer = (props: UsageExplorerProps) => { }, [selectedTime, selectedInterval, selectedService]); useEffect(() => { - props.getServicesList(props.globalTime); + /* + Call the apis only when the route is loaded. + Check this issue: https://github.com/SigNoz/signoz/issues/110 + */ + if (state.USAGE_EXPLORER.isLoaded) { + props.getServicesList(props.globalTime); + } }, []); const data = {