diff --git a/frontend/src/container/GridCardLayout/GridCard/FullView/utils.ts b/frontend/src/container/GridCardLayout/GridCard/FullView/utils.ts index 400394d26e..bbbca2e834 100644 --- a/frontend/src/container/GridCardLayout/GridCard/FullView/utils.ts +++ b/frontend/src/container/GridCardLayout/GridCard/FullView/utils.ts @@ -25,19 +25,26 @@ export const getDefaultTableDataSet = ( data: uPlot.AlignedData, ): ExtendedChartDataset[] => options.series.map( - (item: uPlot.Series, index: number): ExtendedChartDataset => ({ - ...item, - index, - show: true, - sum: convertToTwoDecimalsOrZero( - (data[index] as number[]).reduce((a, b) => a + b, 0), - ), - avg: convertToTwoDecimalsOrZero( - (data[index] as number[]).reduce((a, b) => a + b, 0) / data[index].length, - ), - max: convertToTwoDecimalsOrZero(Math.max(...(data[index] as number[]))), - min: convertToTwoDecimalsOrZero(Math.min(...(data[index] as number[]))), - }), + (item: uPlot.Series, index: number): ExtendedChartDataset => { + let arr: number[]; + if (data[index]) { + arr = data[index] as number[]; + } else { + arr = []; + } + + return { + ...item, + index, + show: true, + sum: convertToTwoDecimalsOrZero(arr.reduce((a, b) => a + b, 0) || 0), + avg: convertToTwoDecimalsOrZero( + (arr.reduce((a, b) => a + b, 0) || 0) / (arr.length || 1), + ), + max: convertToTwoDecimalsOrZero(Math.max(...arr)), + min: convertToTwoDecimalsOrZero(Math.min(...arr)), + }; + }, ); export const getAbbreviatedLabel = (label: string): string => { diff --git a/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx b/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx index ee216280e2..2129220427 100644 --- a/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx +++ b/frontend/src/container/GridCardLayout/GridCard/WidgetGraphComponent.tsx @@ -47,7 +47,7 @@ function WidgetGraphComponent({ const [deleteModal, setDeleteModal] = useState(false); const [hovered, setHovered] = useState(false); const { notifications } = useNotifications(); - const { pathname } = useLocation(); + const { pathname, search } = useLocation(); const params = useUrlQuery(); @@ -183,10 +183,20 @@ function WidgetGraphComponent({ const queryParams = { [QueryParams.expandedWidgetId]: widget.id, }; + const updatedSearch = createQueryParams(queryParams); + const existingSearch = new URLSearchParams(search); + const isExpandedWidgetIdPresent = existingSearch.has( + QueryParams.expandedWidgetId, + ); + if (isExpandedWidgetIdPresent) { + existingSearch.delete(QueryParams.expandedWidgetId); + } + const separator = existingSearch.toString() ? '&' : ''; + const newSearch = `${existingSearch}${separator}${updatedSearch}`; history.push({ pathname, - search: createQueryParams(queryParams), + search: newSearch, }); }; @@ -199,9 +209,12 @@ function WidgetGraphComponent({ }; const onToggleModelHandler = (): void => { + const existingSearchParams = new URLSearchParams(search); + existingSearchParams.delete(QueryParams.expandedWidgetId); + const updatedQueryParams = Object.fromEntries(existingSearchParams.entries()); history.push({ pathname, - search: createQueryParams({}), + search: createQueryParams(updatedQueryParams), }); }; diff --git a/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts b/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts index 31e949111f..9941308838 100644 --- a/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts +++ b/frontend/src/container/MetricsApplication/MetricsApplication.factory.ts @@ -8,9 +8,10 @@ export const getWidgetQueryBuilder = ({ title = '', panelTypes, yAxisUnit = '', + id, }: GetWidgetQueryBuilderProps): Widgets => ({ description: '', - id: v4(), + id: id || v4(), isStacked: false, nullZeroValues: '', opacity: '0', diff --git a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx index 35e77168b4..31ed0769bf 100644 --- a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx @@ -16,7 +16,7 @@ import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { EQueryType } from 'types/common/dashboard'; import { v4 as uuid } from 'uuid'; -import { GraphTitle, MENU_ITEMS } from '../constant'; +import { GraphTitle, MENU_ITEMS, SERVICE_CHART_ID } from '../constant'; import { getWidgetQueryBuilder } from '../MetricsApplication.factory'; import { Card, GraphContainer, Row } from '../styles'; import { Button } from './styles'; @@ -66,6 +66,7 @@ function DBCall(): JSX.Element { title: GraphTitle.DATABASE_CALLS_RPS, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: 'reqps', + id: SERVICE_CHART_ID.dbCallsRPS, }), [servicename, tagFilterItems], ); @@ -85,6 +86,7 @@ function DBCall(): JSX.Element { title: GraphTitle.DATABASE_CALLS_AVG_DURATION, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: 'ms', + id: SERVICE_CHART_ID.dbCallsAvgDuration, }), [servicename, tagFilterItems], ); diff --git a/frontend/src/container/MetricsApplication/Tabs/External.tsx b/frontend/src/container/MetricsApplication/Tabs/External.tsx index cd5eaf3806..7748f8002a 100644 --- a/frontend/src/container/MetricsApplication/Tabs/External.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/External.tsx @@ -17,7 +17,7 @@ import { useParams } from 'react-router-dom'; import { EQueryType } from 'types/common/dashboard'; import { v4 as uuid } from 'uuid'; -import { GraphTitle, legend, MENU_ITEMS } from '../constant'; +import { GraphTitle, legend, MENU_ITEMS, SERVICE_CHART_ID } from '../constant'; import { getWidgetQueryBuilder } from '../MetricsApplication.factory'; import { Card, GraphContainer, Row } from '../styles'; import { Button } from './styles'; @@ -57,6 +57,7 @@ function External(): JSX.Element { title: GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: '%', + id: SERVICE_CHART_ID.externalCallErrorPercentage, }), [servicename, tagFilterItems], ); @@ -82,6 +83,7 @@ function External(): JSX.Element { title: GraphTitle.EXTERNAL_CALL_DURATION, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: 'ms', + id: SERVICE_CHART_ID.externalCallDuration, }), [servicename, tagFilterItems], ); @@ -103,6 +105,7 @@ function External(): JSX.Element { title: GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: 'reqps', + id: SERVICE_CHART_ID.externalCallRPSByAddress, }), [servicename, tagFilterItems], ); @@ -124,6 +127,7 @@ function External(): JSX.Element { title: GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: 'ms', + id: SERVICE_CHART_ID.externalCallDurationByAddress, }), [servicename, tagFilterItems], ); diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx index ff6460e3d7..2b79c861ea 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx @@ -26,7 +26,7 @@ import { GlobalReducer } from 'types/reducer/globalTime'; import { Tags } from 'types/reducer/trace'; import { v4 as uuid } from 'uuid'; -import { GraphTitle } from '../constant'; +import { GraphTitle, SERVICE_CHART_ID } from '../constant'; import { getWidgetQueryBuilder } from '../MetricsApplication.factory'; import { errorPercentage, @@ -131,6 +131,7 @@ function Application(): JSX.Element { title: GraphTitle.RATE_PER_OPS, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: 'ops', + id: SERVICE_CHART_ID.rps, }), [servicename, tagFilterItems, topLevelOperationsRoute], ); @@ -152,6 +153,7 @@ function Application(): JSX.Element { title: GraphTitle.ERROR_PERCENTAGE, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: '%', + id: SERVICE_CHART_ID.errorPercentage, }), [servicename, tagFilterItems, topLevelOperationsRoute], ); diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview/ApDex/ApDexMetrics.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview/ApDex/ApDexMetrics.tsx index d9d134a2a6..e3b03ac577 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview/ApDex/ApDexMetrics.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview/ApDex/ApDexMetrics.tsx @@ -8,7 +8,10 @@ import { import { PANEL_TYPES } from 'constants/queryBuilder'; import Graph from 'container/GridCardLayout/GridCard'; import DisplayThreshold from 'container/GridCardLayout/WidgetHeader/DisplayThreshold'; -import { GraphTitle } from 'container/MetricsApplication/constant'; +import { + GraphTitle, + SERVICE_CHART_ID, +} from 'container/MetricsApplication/constant'; import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory'; import { apDexMetricsQueryBuilderQueries } from 'container/MetricsApplication/MetricsPageQueries/OverviewQueries'; import { ReactNode, useMemo } from 'react'; @@ -59,6 +62,7 @@ function ApDexMetrics({ ), panelTypes: PANEL_TYPES.TIME_SERIES, + id: SERVICE_CHART_ID.apdex, }), [ delta, diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx index ca8fe8c2e2..a6e0e756e1 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx @@ -1,7 +1,10 @@ import { FeatureKeys } from 'constants/features'; import { PANEL_TYPES } from 'constants/queryBuilder'; import Graph from 'container/GridCardLayout/GridCard'; -import { GraphTitle } from 'container/MetricsApplication/constant'; +import { + GraphTitle, + SERVICE_CHART_ID, +} from 'container/MetricsApplication/constant'; import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory'; import { latency } from 'container/MetricsApplication/MetricsPageQueries/OverviewQueries'; import { Card, GraphContainer } from 'container/MetricsApplication/styles'; @@ -59,6 +62,7 @@ function ServiceOverview({ title: GraphTitle.LATENCY, panelTypes: PANEL_TYPES.TIME_SERIES, yAxisUnit: 'ns', + id: SERVICE_CHART_ID.latency, }), [servicename, isSpanMetricEnable, topLevelOperationsRoute, tagFilterItems], ); diff --git a/frontend/src/container/MetricsApplication/constant.ts b/frontend/src/container/MetricsApplication/constant.ts index a6d923c470..1e2958a628 100644 --- a/frontend/src/container/MetricsApplication/constant.ts +++ b/frontend/src/container/MetricsApplication/constant.ts @@ -79,3 +79,17 @@ export const topOperationMetricsDownloadOptions: DownloadOptions = { isDownloadEnabled: true, fileName: 'top-operation', } as const; + +export const SERVICE_CHART_ID = { + latency: 'SERVICE_OVERVIEW_LATENCY', + error: 'SERVICE_OVERVIEW_ERROR', + rps: 'SERVICE_OVERVIEW_RPS', + apdex: 'SERVICE_OVERVIEW_APDEX', + errorPercentage: 'SERVICE_OVERVIEW_ERROR_PERCENTAGE', + dbCallsRPS: 'SERVICE_DATABASE_CALLS_RPS', + dbCallsAvgDuration: 'SERVICE_DATABASE_CALLS_AVG_DURATION', + externalCallDurationByAddress: 'SERVICE_EXTERNAL_CALLS_DURATION_BY_ADDRESS', + externalCallErrorPercentage: 'SERVICE_EXTERNAL_CALLS_ERROR_PERCENTAGE', + externalCallDuration: 'SERVICE_EXTERNAL_CALLS_DURATION', + externalCallRPSByAddress: 'SERVICE_EXTERNAL_CALLS_RPS_BY_ADDRESS', +}; diff --git a/frontend/src/container/MetricsApplication/types.ts b/frontend/src/container/MetricsApplication/types.ts index f87ce66a2a..642bf0b057 100644 --- a/frontend/src/container/MetricsApplication/types.ts +++ b/frontend/src/container/MetricsApplication/types.ts @@ -9,6 +9,7 @@ export interface GetWidgetQueryBuilderProps { title?: ReactNode; panelTypes: Widgets['panelTypes']; yAxisUnit?: Widgets['yAxisUnit']; + id?: Widgets['id']; } export interface NavigateToTraceProps {