diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx deleted file mode 100644 index 3208517b86..0000000000 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/index.metricsBuilder.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { Button } from 'antd'; -import { GraphOnClickHandler } from 'components/Graph'; -import Spinner from 'components/Spinner'; -import TimePreference from 'components/TimePreferenceDropDown'; -import GridGraphComponent from 'container/GridGraphComponent'; -import { - timeItems, - timePreferance, -} from 'container/NewWidget/RightContainer/timeItems'; -import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; -import { useStepInterval } from 'hooks/queryBuilder/useStepInterval'; -import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables'; -import getChartData from 'lib/getChartData'; -import { useCallback, useMemo, useState } from 'react'; -import { useSelector } from 'react-redux'; -import { AppState } from 'store/reducers'; -import { Widgets } from 'types/api/dashboard/getAll'; -import { GlobalReducer } from 'types/reducer/globalTime'; - -import { TimeContainer } from './styles'; - -function FullView({ - widget, - fullViewOptions = true, - onClickHandler, - name, - yAxisUnit, - onDragSelect, - isDependedDataLoaded = false, -}: FullViewProps): JSX.Element { - const { selectedTime: globalSelectedTime } = useSelector< - AppState, - GlobalReducer - >((state) => state.globalTime); - - const getSelectedTime = useCallback( - () => - timeItems.find((e) => e.enum === (widget?.timePreferance || 'GLOBAL_TIME')), - [widget], - ); - - const [selectedTime, setSelectedTime] = useState({ - name: getSelectedTime()?.name || '', - enum: widget?.timePreferance || 'GLOBAL_TIME', - }); - - const queryKey = useMemo( - () => - `FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`, - [selectedTime, globalSelectedTime, widget], - ); - - const updatedQuery = useStepInterval(widget?.query); - - const response = useGetQueryRange( - { - selectedTime: selectedTime.enum, - graphType: widget.panelTypes, - query: updatedQuery, - globalSelectedInterval: globalSelectedTime, - variables: getDashboardVariables(), - }, - { - queryKey, - enabled: !isDependedDataLoaded, - }, - ); - - const chartDataSet = useMemo( - () => - getChartData({ - queryData: [ - { - queryData: response?.data?.payload?.data?.result || [], - }, - ], - }), - [response], - ); - - if (response.status === 'idle' || response.status === 'loading') { - return ; - } - - return ( - <> - {fullViewOptions && ( - - - - - )} - - - - ); -} - -interface FullViewProps { - widget: Widgets; - fullViewOptions?: boolean; - onClickHandler?: GraphOnClickHandler; - name: string; - yAxisUnit?: string; - onDragSelect?: (start: number, end: number) => void; - isDependedDataLoaded?: boolean; -} - -FullView.defaultProps = { - fullViewOptions: undefined, - onClickHandler: undefined, - yAxisUnit: undefined, - onDragSelect: undefined, - isDependedDataLoaded: undefined, -}; - -export default FullView; diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx index 0aefcc109f..3208517b86 100644 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx @@ -1,5 +1,4 @@ -import { Button, Typography } from 'antd'; -import getQueryResult from 'api/widgets/getQuery'; +import { Button } from 'antd'; import { GraphOnClickHandler } from 'components/Graph'; import Spinner from 'components/Spinner'; import TimePreference from 'components/TimePreferenceDropDown'; @@ -7,22 +6,18 @@ import GridGraphComponent from 'container/GridGraphComponent'; import { timeItems, timePreferance, - timePreferenceType, } from 'container/NewWidget/RightContainer/timeItems'; -import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond'; +import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; +import { useStepInterval } from 'hooks/queryBuilder/useStepInterval'; +import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables'; import getChartData from 'lib/getChartData'; -import GetMaxMinTime from 'lib/getMaxMinTime'; -import GetMinMax from 'lib/getMinMax'; -import getStartAndEndTime from 'lib/getStartAndEndTime'; -import getStep from 'lib/getStep'; import { useCallback, useMemo, useState } from 'react'; -import { useQueries } from 'react-query'; import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; -import { PromQLWidgets } from 'types/api/dashboard/getAll'; +import { Widgets } from 'types/api/dashboard/getAll'; import { GlobalReducer } from 'types/reducer/globalTime'; -import { NotFoundContainer, TimeContainer } from './styles'; +import { TimeContainer } from './styles'; function FullView({ widget, @@ -31,8 +26,9 @@ function FullView({ name, yAxisUnit, onDragSelect, + isDependedDataLoaded = false, }: FullViewProps): JSX.Element { - const { minTime, maxTime, selectedTime: globalSelectedTime } = useSelector< + const { selectedTime: globalSelectedTime } = useSelector< AppState, GlobalReducer >((state) => state.globalTime); @@ -48,110 +44,55 @@ function FullView({ enum: widget?.timePreferance || 'GLOBAL_TIME', }); - const maxMinTime = GetMaxMinTime({ - graphType: widget.panelTypes, - maxTime, - minTime, - }); - - const getMinMax = ( - time: timePreferenceType, - ): { min: string | number; max: string | number } => { - if (time === 'GLOBAL_TIME') { - const minMax = GetMinMax(globalSelectedTime, [ - minTime / 1000000, - maxTime / 1000000, - ]); - return { - min: convertToNanoSecondsToSecond(minMax.minTime / 1000), - max: convertToNanoSecondsToSecond(minMax.maxTime / 1000), - }; - } - - const minMax = getStartAndEndTime({ - type: selectedTime.enum, - maxTime: maxMinTime.maxTime, - minTime: maxMinTime.minTime, - }); - return { min: parseInt(minMax.start, 10), max: parseInt(minMax.end, 10) }; - }; - - const queryMinMax = getMinMax(selectedTime.enum); - - const queryLength = widget.query.filter((e) => e.query.length !== 0); - - const response = useQueries( - queryLength.map((query) => ({ - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - queryFn: () => - getQueryResult({ - end: queryMinMax.max.toString(), - query: query.query, - start: queryMinMax.min.toString(), - step: `${getStep({ - start: queryMinMax.min, - end: queryMinMax.max, - inputFormat: 's', - })}`, - }), - queryHash: `${query.query}-${query.legend}-${selectedTime.enum}`, - retryOnMount: false, - })), + const queryKey = useMemo( + () => + `FullViewGetMetricsQueryRange-${selectedTime.enum}-${globalSelectedTime}-${widget.id}`, + [selectedTime, globalSelectedTime, widget], ); - const isError = - response.find((e) => e?.data?.statusCode !== 200) !== undefined || - response.some((e) => e.isError === true); + const updatedQuery = useStepInterval(widget?.query); - const isLoading = response.some((e) => e.isLoading === true); - - const errorMessage = response.find((e) => e.data?.error !== null)?.data?.error; - - const data = response.map((responseOfQuery) => - responseOfQuery?.data?.payload?.result.map((e, index) => ({ - query: queryLength[index]?.query, - queryData: e, - legend: queryLength[index]?.legend, - })), + const response = useGetQueryRange( + { + selectedTime: selectedTime.enum, + graphType: widget.panelTypes, + query: updatedQuery, + globalSelectedInterval: globalSelectedTime, + variables: getDashboardVariables(), + }, + { + queryKey, + enabled: !isDependedDataLoaded, + }, ); const chartDataSet = useMemo( () => getChartData({ - queryData: data.map((e) => ({ - query: e?.map((e) => e.query).join(' ') || '', - queryData: e?.map((e) => e.queryData) || [], - legend: e?.map((e) => e.legend).join('') || '', - })), + queryData: [ + { + queryData: response?.data?.payload?.data?.result || [], + }, + ], }), - [data], + [response], ); - if (isLoading) { + if (response.status === 'idle' || response.status === 'loading') { return ; } - if (isError || data === undefined || data[0] === undefined) { - return ( - - {errorMessage} - - ); - } - return ( <> {fullViewOptions && ( - Database Calls RPS - { @@ -108,6 +114,9 @@ function DBCall(): JSX.Element { 'database_call_rps', ); }} + allowClone={false} + allowDelete={false} + allowEdit={false} /> @@ -127,11 +136,9 @@ function DBCall(): JSX.Element { View Traces - Database Calls Avg Duration - { @@ -143,6 +150,9 @@ function DBCall(): JSX.Element { 'database_call_avg_duration', ); }} + allowClone={false} + allowDelete={false} + allowEdit={false} /> diff --git a/frontend/src/container/MetricsApplication/Tabs/External.tsx b/frontend/src/container/MetricsApplication/Tabs/External.tsx index 36f3235730..ab1e99f430 100644 --- a/frontend/src/container/MetricsApplication/Tabs/External.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/External.tsx @@ -1,5 +1,5 @@ import { Col } from 'antd'; -import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder'; +import Graph from 'container/GridGraphLayout/Graph/'; import { externalCallDuration, externalCallDurationByAddress, @@ -16,10 +16,11 @@ import { useParams } from 'react-router-dom'; import { EQueryType } from 'types/common/dashboard'; import { v4 as uuid } from 'uuid'; +import { GraphTitle, legend } from '../constant'; import { getWidgetQueryBuilder } from '../MetricsApplication.factory'; -import { Card, GraphContainer, GraphTitle, Row } from '../styles'; -import { legend } from './constant'; +import { Card, GraphContainer, Row } from '../styles'; import { Button } from './styles'; +import { IServiceName } from './types'; import { handleNonInQueryRange, onGraphClickHandler, @@ -29,7 +30,7 @@ import { function External(): JSX.Element { const [selectedTimeStamp, setSelectedTimeStamp] = useState(0); - const { servicename } = useParams<{ servicename?: string }>(); + const { servicename } = useParams(); const { queries } = useResourceAttribute(); const tagFilterItems = useMemo( @@ -40,17 +41,20 @@ function External(): JSX.Element { const externalCallErrorWidget = useMemo( () => - getWidgetQueryBuilder({ - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: externalCallErrorPercent({ - servicename, - legend: legend.address, - tagFilterItems, - }), - clickhouse_sql: [], - id: uuid(), - }), + getWidgetQueryBuilder( + { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: externalCallErrorPercent({ + servicename, + legend: legend.address, + tagFilterItems, + }), + clickhouse_sql: [], + id: uuid(), + }, + GraphTitle.EXTERNAL_CALL_ERROR_PERCENTAGE, + ), [servicename, tagFilterItems], ); @@ -61,48 +65,57 @@ function External(): JSX.Element { const externalCallDurationWidget = useMemo( () => - getWidgetQueryBuilder({ - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: externalCallDuration({ - servicename, - tagFilterItems, - }), - clickhouse_sql: [], - id: uuid(), - }), + getWidgetQueryBuilder( + { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: externalCallDuration({ + servicename, + tagFilterItems, + }), + clickhouse_sql: [], + id: uuid(), + }, + GraphTitle.EXTERNAL_CALL_DURATION, + ), [servicename, tagFilterItems], ); const externalCallRPSWidget = useMemo( () => - getWidgetQueryBuilder({ - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: externalCallRpsByAddress({ - servicename, - legend: legend.address, - tagFilterItems, - }), - clickhouse_sql: [], - id: uuid(), - }), + getWidgetQueryBuilder( + { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: externalCallRpsByAddress({ + servicename, + legend: legend.address, + tagFilterItems, + }), + clickhouse_sql: [], + id: uuid(), + }, + GraphTitle.EXTERNAL_CALL_RPS_BY_ADDRESS, + ), [servicename, tagFilterItems], ); const externalCallDurationAddressWidget = useMemo( () => - getWidgetQueryBuilder({ - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: externalCallDurationByAddress({ - servicename, - legend: legend.address, - tagFilterItems, - }), - clickhouse_sql: [], - id: uuid(), - }), + getWidgetQueryBuilder( + { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: externalCallDurationByAddress({ + servicename, + legend: legend.address, + tagFilterItems, + }), + clickhouse_sql: [], + id: uuid(), + }, + GraphTitle.EXTERNAL_CALL_DURATION_BY_ADDRESS, + ), [servicename, tagFilterItems], ); @@ -124,11 +137,9 @@ function External(): JSX.Element { View Traces - External Call Error Percentage - { @@ -140,6 +151,9 @@ function External(): JSX.Element { 'external_call_error_percentage', ); }} + allowClone={false} + allowDelete={false} + allowEdit={false} /> @@ -161,11 +175,9 @@ function External(): JSX.Element { - External Call duration - { @@ -177,6 +189,9 @@ function External(): JSX.Element { 'external_call_duration', ); }} + allowClone={false} + allowDelete={false} + allowEdit={false} /> @@ -199,11 +214,9 @@ function External(): JSX.Element { View Traces - External Call RPS(by Address) - { @@ -215,6 +228,9 @@ function External(): JSX.Element { 'external_call_rps_by_address', ); }} + allowClone={false} + allowDelete={false} + allowEdit={false} /> @@ -236,11 +252,9 @@ function External(): JSX.Element { - External Call duration(by Address) - { @@ -252,6 +266,9 @@ function External(): JSX.Element { 'external_call_duration_by_address', ); }} + allowClone={false} + allowDelete={false} + allowEdit={false} /> diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx index 5cd571a548..542449ba97 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx @@ -1,16 +1,9 @@ -import { Typography } from 'antd'; -import getServiceOverview from 'api/metrics/getServiceOverview'; import getTopLevelOperations, { ServiceDataProps, } from 'api/metrics/getTopLevelOperations'; -import getTopOperations from 'api/metrics/getTopOperations'; -import axios from 'axios'; import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js'; -import Graph from 'components/Graph'; -import Spinner from 'components/Spinner'; import { QueryParams } from 'constants/query'; import ROUTES from 'constants/routes'; -import FullView from 'container/GridGraphLayout/Graph/FullView/index.metricsBuilder'; import { routeConfig } from 'container/SideNav/config'; import { getQueryString } from 'container/SideNav/helper'; import useResourceAttribute from 'hooks/useResourceAttribute'; @@ -18,32 +11,30 @@ import { convertRawQueriesToTraceSelectedTags, resourceAttributesToTagFilterItems, } from 'hooks/useResourceAttribute/utils'; -import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond'; -import { colors } from 'lib/getRandomColor'; -import getStep from 'lib/getStep'; import history from 'lib/history'; import { useCallback, useMemo, useState } from 'react'; -import { useQueries, UseQueryResult } from 'react-query'; +import { useQuery } from 'react-query'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation, useParams } from 'react-router-dom'; import { UpdateTimeInterval } from 'store/actions'; import { AppState } from 'store/reducers'; -import { PayloadProps } from 'types/api/metrics/getServiceOverview'; -import { PayloadProps as PayloadPropsTopOpertions } from 'types/api/metrics/getTopOperations'; import { EQueryType } from 'types/common/dashboard'; import { GlobalReducer } from 'types/reducer/globalTime'; import { Tags } from 'types/reducer/trace'; import { v4 as uuid } from 'uuid'; -import { SOMETHING_WENT_WRONG } from '../../../constants/api'; +import { GraphTitle } from '../constant'; import { getWidgetQueryBuilder } from '../MetricsApplication.factory'; import { errorPercentage, operationPerSec, } from '../MetricsPageQueries/OverviewQueries'; -import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles'; -import TopOperationsTable from '../TopOperationsTable'; +import { Col, Row } from '../styles'; +import ServiceOverview from './Overview/ServiceOverview'; +import TopLevelOperation from './Overview/TopLevelOperations'; +import TopOperation from './Overview/TopOperation'; import { Button } from './styles'; +import { IServiceName } from './types'; import { handleNonInQueryRange, onGraphClickHandler, @@ -54,7 +45,7 @@ function Application(): JSX.Element { const { maxTime, minTime } = useSelector( (state) => state.globalTime, ); - const { servicename } = useParams<{ servicename?: string }>(); + const { servicename } = useParams(); const [selectedTimeStamp, setSelectedTimeStamp] = useState(0); const { search } = useLocation(); const { queries } = useResourceAttribute(); @@ -86,53 +77,15 @@ function Application(): JSX.Element { [handleSetTimeStamp], ); - const queryResult = useQueries< - [ - UseQueryResult, - UseQueryResult, - UseQueryResult, - ] - >([ - { - queryKey: [servicename, selectedTags, minTime, maxTime], - queryFn: (): Promise => - getServiceOverview({ - service: servicename || '', - start: minTime, - end: maxTime, - step: getStep({ - start: minTime, - end: maxTime, - inputFormat: 'ns', - }), - selectedTags, - }), - }, - { - queryKey: [minTime, maxTime, servicename, selectedTags], - queryFn: (): Promise => - getTopOperations({ - service: servicename || '', - start: minTime, - end: maxTime, - selectedTags, - }), - }, - { - queryKey: [servicename, minTime, maxTime, selectedTags], - queryFn: (): Promise => getTopLevelOperations(), - }, - ]); - - const serviceOverview = queryResult[0].data; - const serviceOverviewError = queryResult[0].error; - const serviceOverviewIsError = queryResult[0].isError; - const serviceOverviewIsLoading = queryResult[0].isLoading; - const topOperations = queryResult[1].data; - const topLevelOperations = queryResult[2].data; - const topLevelOperationsError = queryResult[2].error; - const topLevelOperationsIsError = queryResult[2].isError; - const topLevelOperationsIsLoading = queryResult[2].isLoading; + const { + data: topLevelOperations, + isLoading: topLevelOperationsLoading, + error: topLevelOperationsError, + isError: topLevelOperationsIsError, + } = useQuery({ + queryKey: [servicename, minTime, maxTime, selectedTags], + queryFn: getTopLevelOperations, + }); const selectedTraceTags: string = JSON.stringify( convertRawQueriesToTraceSelectedTags(queries) || [], @@ -146,37 +99,43 @@ function Application(): JSX.Element { const operationPerSecWidget = useMemo( () => - getWidgetQueryBuilder({ - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: operationPerSec({ - servicename, - tagFilterItems, - topLevelOperations: topLevelOperations - ? topLevelOperations[servicename || ''] - : [], - }), - clickhouse_sql: [], - id: uuid(), - }), + getWidgetQueryBuilder( + { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: operationPerSec({ + servicename, + tagFilterItems, + topLevelOperations: topLevelOperations + ? topLevelOperations[servicename || ''] + : [], + }), + clickhouse_sql: [], + id: uuid(), + }, + GraphTitle.RATE_PER_OPS, + ), [servicename, topLevelOperations, tagFilterItems], ); const errorPercentageWidget = useMemo( () => - getWidgetQueryBuilder({ - queryType: EQueryType.QUERY_BUILDER, - promql: [], - builder: errorPercentage({ - servicename, - tagFilterItems, - topLevelOperations: topLevelOperations - ? topLevelOperations[servicename || ''] - : [], - }), - clickhouse_sql: [], - id: uuid(), - }), + getWidgetQueryBuilder( + { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: errorPercentage({ + servicename, + tagFilterItems, + topLevelOperations: topLevelOperations + ? topLevelOperations[servicename || ''] + : [], + }), + clickhouse_sql: [], + id: uuid(), + }, + GraphTitle.ERROR_PERCENTAGE, + ), [servicename, topLevelOperations, tagFilterItems], ); @@ -212,107 +171,17 @@ function Application(): JSX.Element { ); }; - const generalChartDataProperties = useCallback( - (title: string, colorIndex: number) => ({ - borderColor: colors[colorIndex], - label: title, - showLine: true, - borderWidth: 1.5, - spanGaps: true, - pointRadius: 2, - pointHoverRadius: 4, - }), - [], - ); - - const dataSets = useMemo(() => { - if (!serviceOverview) { - return []; - } - - return [ - { - data: serviceOverview.map((e) => - parseFloat(convertToNanoSecondsToSecond(e.p99)), - ), - ...generalChartDataProperties('p99 Latency', 0), - }, - { - data: serviceOverview.map((e) => - parseFloat(convertToNanoSecondsToSecond(e.p95)), - ), - ...generalChartDataProperties('p95 Latency', 1), - }, - { - data: serviceOverview.map((e) => - parseFloat(convertToNanoSecondsToSecond(e.p50)), - ), - ...generalChartDataProperties('p50 Latency', 2), - }, - ]; - }, [generalChartDataProperties, serviceOverview]); - - const data = useMemo(() => { - if (!serviceOverview) { - return { - datasets: [], - labels: [], - }; - } - - return { - datasets: dataSets, - labels: serviceOverview.map( - (e) => new Date(parseFloat(convertToNanoSecondsToSecond(e.timestamp))), - ), - }; - }, [serviceOverview, dataSets]); - return ( <> - - - {serviceOverviewIsError ? ( - - {axios.isAxiosError(serviceOverviewError) - ? serviceOverviewError.response?.data - : SOMETHING_WENT_WRONG} - - ) : ( - <> - Latency - {serviceOverviewIsLoading && ( - - )} - {!serviceOverviewIsLoading && ( - - - - )} - - )} - + @@ -328,30 +197,17 @@ function Application(): JSX.Element { > View Traces - - {topLevelOperationsIsError ? ( - - {axios.isAxiosError(topLevelOperationsError) - ? topLevelOperationsError.response?.data - : SOMETHING_WENT_WRONG} - - ) : ( - <> - Rate (ops/s) - - - - - )} - + @@ -367,43 +223,28 @@ function Application(): JSX.Element { View Traces - - {topLevelOperationsIsError ? ( - - {axios.isAxiosError(topLevelOperationsError) - ? topLevelOperationsError.response?.data - : SOMETHING_WENT_WRONG} - - ) : ( - <> - Error Percentage - - - - - )} - + - - - + ); } -type ClickHandlerType = ( +export type ClickHandlerType = ( ChartEvent: ChartEvent, activeElements: ActiveElement[], chart: Chart, diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx new file mode 100644 index 0000000000..342ddc191d --- /dev/null +++ b/frontend/src/container/MetricsApplication/Tabs/Overview/ServiceOverview.tsx @@ -0,0 +1,84 @@ +import Graph from 'container/GridGraphLayout/Graph/'; +import { GraphTitle } 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'; +import { useMemo } from 'react'; +import { useParams } from 'react-router-dom'; +import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; +import { EQueryType } from 'types/common/dashboard'; +import { v4 as uuid } from 'uuid'; + +import { ClickHandlerType } from '../Overview'; +import { Button } from '../styles'; +import { IServiceName } from '../types'; +import { onViewTracePopupClick } from '../util'; + +function ServiceOverview({ + onDragSelect, + handleGraphClick, + selectedTraceTags, + selectedTimeStamp, + tagFilterItems, +}: ServiceOverviewProps): JSX.Element { + const { servicename } = useParams(); + + const latencyWidget = useMemo( + () => + getWidgetQueryBuilder( + { + queryType: EQueryType.QUERY_BUILDER, + promql: [], + builder: latency({ + servicename, + tagFilterItems, + }), + clickhouse_sql: [], + id: uuid(), + }, + GraphTitle.LATENCY, + ), + [servicename, tagFilterItems], + ); + + return ( + <> + + + + + + + + ); +} + +interface ServiceOverviewProps { + selectedTimeStamp: number; + selectedTraceTags: string; + onDragSelect: (start: number, end: number) => void; + handleGraphClick: (type: string) => ClickHandlerType; + tagFilterItems: TagFilterItem[]; +} + +export default ServiceOverview; diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview/TopLevelOperations.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview/TopLevelOperations.tsx new file mode 100644 index 0000000000..6d4a624a04 --- /dev/null +++ b/frontend/src/container/MetricsApplication/Tabs/Overview/TopLevelOperations.tsx @@ -0,0 +1,65 @@ +import { Typography } from 'antd'; +import axios from 'axios'; +import Spinner from 'components/Spinner'; +import { SOMETHING_WENT_WRONG } from 'constants/api'; +import Graph from 'container/GridGraphLayout/Graph/'; +import { Card, GraphContainer } from 'container/MetricsApplication/styles'; +import { Widgets } from 'types/api/dashboard/getAll'; + +import { ClickHandlerType } from '../Overview'; + +function TopLevelOperation({ + name, + opName, + topLevelOperationsIsError, + topLevelOperationsError, + topLevelOperationsLoading, + onDragSelect, + handleGraphClick, + widget, + yAxisUnit, +}: TopLevelOperationProps): JSX.Element { + return ( + + {topLevelOperationsIsError ? ( + + {axios.isAxiosError(topLevelOperationsError) + ? topLevelOperationsError.response?.data + : SOMETHING_WENT_WRONG} + + ) : ( + + {topLevelOperationsLoading && ( + + )} + {!topLevelOperationsLoading && ( + + )} + + )} + + ); +} + +interface TopLevelOperationProps { + name: string; + opName: string; + topLevelOperationsIsError: boolean; + topLevelOperationsError: unknown; + topLevelOperationsLoading: boolean; + onDragSelect: (start: number, end: number) => void; + handleGraphClick: (type: string) => ClickHandlerType; + widget: Widgets; + yAxisUnit: string; +} + +export default TopLevelOperation; diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview/TopOperation.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview/TopOperation.tsx new file mode 100644 index 0000000000..183ec20e7a --- /dev/null +++ b/frontend/src/container/MetricsApplication/Tabs/Overview/TopOperation.tsx @@ -0,0 +1,46 @@ +import getTopOperations from 'api/metrics/getTopOperations'; +import Spinner from 'components/Spinner'; +import { Card } from 'container/MetricsApplication/styles'; +import TopOperationsTable from 'container/MetricsApplication/TopOperationsTable'; +import useResourceAttribute from 'hooks/useResourceAttribute'; +import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils'; +import { useMemo } from 'react'; +import { useQuery } from 'react-query'; +import { useSelector } from 'react-redux'; +import { useParams } from 'react-router-dom'; +import { AppState } from 'store/reducers'; +import { PayloadProps } from 'types/api/metrics/getTopOperations'; +import { GlobalReducer } from 'types/reducer/globalTime'; +import { Tags } from 'types/reducer/trace'; + +function TopOperation(): JSX.Element { + const { maxTime, minTime } = useSelector( + (state) => state.globalTime, + ); + const { servicename } = useParams<{ servicename?: string }>(); + const { queries } = useResourceAttribute(); + const selectedTags = useMemo( + () => (convertRawQueriesToTraceSelectedTags(queries) as Tags[]) || [], + [queries], + ); + + const { data, isLoading } = useQuery({ + queryKey: [minTime, maxTime, servicename, selectedTags], + queryFn: (): Promise => + getTopOperations({ + service: servicename || '', + start: minTime, + end: maxTime, + selectedTags, + }), + }); + + return ( + + {isLoading && } + {!isLoading && } + + ); +} + +export default TopOperation; diff --git a/frontend/src/container/MetricsApplication/Tabs/constant.ts b/frontend/src/container/MetricsApplication/Tabs/constant.ts deleted file mode 100644 index 4931667e6e..0000000000 --- a/frontend/src/container/MetricsApplication/Tabs/constant.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const legend = { - address: '{{address}}', -}; diff --git a/frontend/src/container/MetricsApplication/Tabs/types.ts b/frontend/src/container/MetricsApplication/Tabs/types.ts new file mode 100644 index 0000000000..2d60b132ee --- /dev/null +++ b/frontend/src/container/MetricsApplication/Tabs/types.ts @@ -0,0 +1,3 @@ +export interface IServiceName { + servicename: string; +} diff --git a/frontend/src/container/MetricsApplication/constant.ts b/frontend/src/container/MetricsApplication/constant.ts new file mode 100644 index 0000000000..6ceead671d --- /dev/null +++ b/frontend/src/container/MetricsApplication/constant.ts @@ -0,0 +1,53 @@ +export const legend = { + address: '{{address}}', +}; + +export const QUERYNAME_AND_EXPRESSION = ['A', 'B', 'C']; +export const LETENCY_LEGENDS_AGGREGATEOPERATOR = ['p50', 'p90', 'p99']; +export const OPERATION_LEGENDS = ['Operations']; + +export enum FORMULA { + ERROR_PERCENTAGE = 'A*100/B', + DATABASE_CALLS_AVG_DURATION = 'A/B', +} + +export enum GraphTitle { + LATENCY = 'Latency', + RATE_PER_OPS = 'Rate (ops/s)', + ERROR_PERCENTAGE = 'Error Percentage', + DATABASE_CALLS_RPS = 'Database Calls RPS', + DATABASE_CALLS_AVG_DURATION = 'Database Calls Avg Duration', + EXTERNAL_CALL_ERROR_PERCENTAGE = 'External Call Error Percentage', + EXTERNAL_CALL_DURATION = 'External Call duration', + EXTERNAL_CALL_RPS_BY_ADDRESS = 'External Call RPS(by Address)', + EXTERNAL_CALL_DURATION_BY_ADDRESS = 'External Call duration(by Address)', +} + +export enum DataType { + STRING = 'string', + FLOAT64 = 'float64', + INT64 = 'int64', +} + +export enum MetricsType { + Tag = 'tag', + Resource = 'resource', +} + +export enum WidgetKeys { + Address = 'address', + DurationNano = 'durationNano', + StatusCode = 'status_code', + Operation = 'operation', + OperationName = 'operationName', + Service_name = 'service_name', + ServiceName = 'serviceName', + SignozLatencyCount = 'signoz_latency_count', + SignozDBLatencyCount = 'signoz_db_latency_count', + DatabaseCallCount = 'signoz_database_call_count', + DatabaseCallLatencySum = 'signoz_database_call_latency_sum', + SignozDbLatencySum = 'signoz_db_latency_sum', + SignozCallsTotal = 'signoz_calls_total', + SignozExternalCallLatencyCount = 'signoz_external_call_latency_count', + SignozExternalCallLatencySum = 'signoz_external_call_latency_sum', +} diff --git a/frontend/src/utils/dashboard/selectedDashboard.ts b/frontend/src/utils/dashboard/selectedDashboard.ts new file mode 100644 index 0000000000..c05077f39c --- /dev/null +++ b/frontend/src/utils/dashboard/selectedDashboard.ts @@ -0,0 +1,18 @@ +import { Dashboard, IDashboardVariable } from 'types/api/dashboard/getAll'; + +export const getSelectedDashboard = (dashboard: Dashboard[]): Dashboard => { + if (dashboard.length > 0) { + return dashboard[0]; + } + return {} as Dashboard; +}; + +export const getSelectedDashboardVariable = ( + dashboard: Dashboard[], +): Record => { + if (dashboard.length > 0) { + const { variables } = dashboard[0].data; + return variables; + } + return {}; +};