diff --git a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx index a2549ada33..f5ce2a0188 100644 --- a/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/DBCall.tsx @@ -17,6 +17,7 @@ import { Card, GraphContainer, GraphTitle, Row } from '../styles'; import { Button } from './styles'; import { dbSystemTags, + handleNonInQueryRange, onGraphClickHandler, onViewTracePopupClick, } from './util'; @@ -25,10 +26,13 @@ function DBCall({ getWidgetQueryBuilder }: DBCallProps): JSX.Element { const { servicename } = useParams<{ servicename?: string }>(); const [selectedTimeStamp, setSelectedTimeStamp] = useState(0); const { queries } = useResourceAttribute(); + const tagFilterItems = useMemo( - () => resourceAttributesToTagFilterItems(queries) || [], + () => + handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [], [queries], ); + const selectedTraceTags: string = useMemo( () => JSON.stringify( diff --git a/frontend/src/container/MetricsApplication/Tabs/External.tsx b/frontend/src/container/MetricsApplication/Tabs/External.tsx index e4797d8bc1..c615179d65 100644 --- a/frontend/src/container/MetricsApplication/Tabs/External.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/External.tsx @@ -18,7 +18,11 @@ import { Widgets } from 'types/api/dashboard/getAll'; import { Card, GraphContainer, GraphTitle, Row } from '../styles'; import { legend } from './constant'; import { Button } from './styles'; -import { onGraphClickHandler, onViewTracePopupClick } from './util'; +import { + handleNonInQueryRange, + onGraphClickHandler, + onViewTracePopupClick, +} from './util'; function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element { const [selectedTimeStamp, setSelectedTimeStamp] = useState(0); @@ -27,7 +31,8 @@ function External({ getWidgetQueryBuilder }: ExternalProps): JSX.Element { const { queries } = useResourceAttribute(); const tagFilterItems = useMemo( - () => resourceAttributesToTagFilterItems(queries) || [], + () => + handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [], [queries], ); diff --git a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx index 270475eaf9..f540a69896 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Overview.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Overview.tsx @@ -26,7 +26,11 @@ import { import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles'; import TopOperationsTable from '../TopOperationsTable'; import { Button } from './styles'; -import { onGraphClickHandler, onViewTracePopupClick } from './util'; +import { + handleNonInQueryRange, + onGraphClickHandler, + onViewTracePopupClick, +} from './util'; function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element { const { servicename } = useParams<{ servicename?: string }>(); @@ -67,7 +71,8 @@ function Application({ getWidgetQueryBuilder }: DashboardProps): JSX.Element { ); const tagFilterItems = useMemo( - () => resourceAttributesToTagFilterItems(queries) || [], + () => + handleNonInQueryRange(resourceAttributesToTagFilterItems(queries)) || [], [queries], ); diff --git a/frontend/src/container/MetricsApplication/Tabs/util.ts b/frontend/src/container/MetricsApplication/Tabs/util.ts index a8b53d6f62..aa02902597 100644 --- a/frontend/src/container/MetricsApplication/Tabs/util.ts +++ b/frontend/src/container/MetricsApplication/Tabs/util.ts @@ -2,6 +2,7 @@ import { ActiveElement, Chart, ChartData, ChartEvent } from 'chart.js'; import { METRICS_PAGE_QUERY_PARAM } from 'constants/query'; import ROUTES from 'constants/routes'; import history from 'lib/history'; +import { IQueryBuilderTagFilterItems } from 'types/api/dashboard/getAll'; import { Tags } from 'types/reducer/trace'; export const dbSystemTags: Tags[] = [ @@ -84,3 +85,16 @@ export function onGraphClickHandler( } }; } + +export const handleNonInQueryRange = ( + tags: IQueryBuilderTagFilterItems[], +): IQueryBuilderTagFilterItems[] => + tags.map((tag) => { + if (tag.op === 'Not IN') { + return { + ...tag, + op: 'NIN', + }; + } + return tag; + }); diff --git a/frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx b/frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx index 0b9c8df955..848a7c3ca0 100644 --- a/frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx +++ b/frontend/src/hooks/useResourceAttribute/ResourceProvider.tsx @@ -17,7 +17,6 @@ import { GetTagKeys, GetTagValues, OperatorSchema, - resourceAttributesQueryToPromQL, } from './utils'; function ResourceProvider({ children }: Props): JSX.Element { @@ -29,10 +28,6 @@ function ResourceProvider({ children }: Props): JSX.Element { getResourceAttributeQueriesFromURL(), ); - const [promQLQuery, setpromQLQuery] = useState( - resourceAttributesQueryToPromQL(queries), - ); - const [optionsData, setOptionsData] = useState({ mode: undefined, options: [], @@ -55,7 +50,6 @@ function ResourceProvider({ children }: Props): JSX.Element { : '', }); setQueries(queries); - setpromQLQuery(resourceAttributesQueryToPromQL(queries)); }, [pathname], ); @@ -144,7 +138,6 @@ function ResourceProvider({ children }: Props): JSX.Element { () => ({ queries, staging, - promQLQuery, handleClearAll, handleClose, handleBlur, @@ -161,7 +154,6 @@ function ResourceProvider({ children }: Props): JSX.Element { handleClose, handleFocus, loading, - promQLQuery, queries, staging, selectedQuery, diff --git a/frontend/src/hooks/useResourceAttribute/types.ts b/frontend/src/hooks/useResourceAttribute/types.ts index e6f4b47016..422a0555ba 100644 --- a/frontend/src/hooks/useResourceAttribute/types.ts +++ b/frontend/src/hooks/useResourceAttribute/types.ts @@ -20,7 +20,6 @@ export interface OptionsData { export interface IResourceAttributeProps { queries: IResourceAttribute[]; staging: string[]; - promQLQuery: string; handleClearAll: VoidFunction; handleClose: (id: string) => void; handleBlur: VoidFunction; diff --git a/frontend/src/hooks/useResourceAttribute/utils.ts b/frontend/src/hooks/useResourceAttribute/utils.ts index ad44918070..f51211f733 100644 --- a/frontend/src/hooks/useResourceAttribute/utils.ts +++ b/frontend/src/hooks/useResourceAttribute/utils.ts @@ -57,26 +57,6 @@ export const convertRawQueriesToTraceSelectedTags = ( TagType: tagType, })); -/** - * Converts Resource Attribute Queries to PromQL query string - */ -export const resourceAttributesQueryToPromQL = ( - queries: IResourceAttribute[], -): string => { - let parsedQueryString = ''; - - if (Array.isArray(queries)) - queries.forEach((query) => { - parsedQueryString += `, ${ - query.tagKey - }${convertOperatorLabelToMetricOperator( - query.operator, - )}"${query.tagValue.join('|')}"`; - }); - - return parsedQueryString; -}; - /* Convert resource attributes to tagFilter items for queryBuilder */ export const resourceAttributesToTagFilterItems = ( queries: IResourceAttribute[], diff --git a/frontend/src/modules/Servicemap/Map.tsx b/frontend/src/modules/Servicemap/Map.tsx new file mode 100644 index 0000000000..e9125c84f5 --- /dev/null +++ b/frontend/src/modules/Servicemap/Map.tsx @@ -0,0 +1,56 @@ +/* eslint-disable */ +//@ts-nocheck +import { useIsDarkMode } from 'hooks/useDarkMode'; +import React, { memo } from 'react'; +import { ForceGraph2D } from 'react-force-graph'; + +import { getGraphData, getTooltip, transformLabel } from './utils'; + +function Map({ fgRef, serviceMap }: any): JSX.Element { + const isDarkMode = useIsDarkMode(); + + const { nodes, links } = getGraphData(serviceMap, isDarkMode); + + const graphData = { nodes, links }; + + return ( + d.target} + linkDirectionalParticles="value" + linkDirectionalParticleSpeed={(d) => d.value} + nodeCanvasObject={(node, ctx) => { + const label = transformLabel(node.id); + const { fontSize } = node; + ctx.font = `${fontSize}px Roboto`; + const { width } = node; + + ctx.fillStyle = node.color; + ctx.beginPath(); + ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false); + ctx.fill(); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = isDarkMode ? '#ffffff' : '#000000'; + ctx.fillText(label, node.x, node.y); + }} + onLinkHover={(node) => { + const tooltip = document.querySelector('.graph-tooltip'); + if (tooltip && node) { + tooltip.innerHTML = getTooltip(node); + } + }} + nodePointerAreaPaint={(node, color, ctx) => { + ctx.fillStyle = color; + ctx.beginPath(); + ctx.arc(node.x, node.y, 5, 0, 2 * Math.PI, false); + ctx.fill(); + }} + /> + ); +} + +export default memo(Map); diff --git a/frontend/src/modules/Servicemap/ServiceMap.tsx b/frontend/src/modules/Servicemap/ServiceMap.tsx index 9c36aa7e18..5e92bdbb37 100644 --- a/frontend/src/modules/Servicemap/ServiceMap.tsx +++ b/frontend/src/modules/Servicemap/ServiceMap.tsx @@ -3,9 +3,10 @@ import { Card } from 'antd'; import Spinner from 'components/Spinner'; -import { useIsDarkMode } from 'hooks/useDarkMode'; +import ResourceAttributesFilter from 'container/ResourceAttributesFilter'; +import useResourceAttribute from 'hooks/useResourceAttribute'; +import { IResourceAttribute } from 'hooks/useResourceAttribute/types'; import React, { useEffect, useRef } from 'react'; -import { ForceGraph2D } from 'react-force-graph'; import { connect } from 'react-redux'; import { RouteComponentProps, withRouter } from 'react-router-dom'; import { getDetailedServiceMapItems, ServiceMapStore } from 'store/actions'; @@ -13,7 +14,7 @@ import { AppState } from 'store/reducers'; import styled from 'styled-components'; import { GlobalTime } from 'types/actions/globalTime'; -import { getGraphData, getTooltip, getZoomPx, transformLabel } from './utils'; +import Map from './Map'; const Container = styled.div` .force-graph-container { @@ -38,7 +39,10 @@ const Container = styled.div` interface ServiceMapProps extends RouteComponentProps { serviceMap: ServiceMapStore; globalTime: GlobalTime; - getDetailedServiceMapItems: (time: GlobalTime) => void; + getDetailedServiceMapItems: ( + time: GlobalTime, + queries: IResourceAttribute[], + ) => void; } interface graphNode { id: string; @@ -60,17 +64,17 @@ export interface graphDataType { function ServiceMap(props: ServiceMapProps): JSX.Element { const fgRef = useRef(); - const isDarkMode = useIsDarkMode(); - const { getDetailedServiceMapItems, globalTime, serviceMap } = props; + const { queries } = useResourceAttribute(); + useEffect(() => { /* Call the apis only when the route is loaded. Check this issue: https://github.com/SigNoz/signoz/issues/110 */ - getDetailedServiceMapItems(globalTime); - }, [globalTime, getDetailedServiceMapItems]); + getDetailedServiceMapItems(globalTime, queries); + }, [globalTime, getDetailedServiceMapItems, queries]); useEffect(() => { fgRef.current && fgRef.current.d3Force('charge').strength(-400); @@ -83,51 +87,15 @@ function ServiceMap(props: ServiceMapProps): JSX.Element { if (!serviceMap.loading && serviceMap.items.length === 0) { return ( + No Service Found ); } - - const { nodes, links } = getGraphData(serviceMap, isDarkMode); - const graphData = { nodes, links }; return ( - d.target} - linkDirectionalParticles="value" - linkDirectionalParticleSpeed={(d) => d.value} - nodeCanvasObject={(node, ctx) => { - const label = transformLabel(node.id); - const { fontSize } = node; - ctx.font = `${fontSize}px Roboto`; - const { width } = node; - - ctx.fillStyle = node.color; - ctx.beginPath(); - ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false); - ctx.fill(); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = isDarkMode ? '#ffffff' : '#000000'; - ctx.fillText(label, node.x, node.y); - }} - onLinkHover={(node) => { - const tooltip = document.querySelector('.graph-tooltip'); - if (tooltip && node) { - tooltip.innerHTML = getTooltip(node); - } - }} - nodePointerAreaPaint={(node, color, ctx) => { - ctx.fillStyle = color; - ctx.beginPath(); - ctx.arc(node.x, node.y, 5, 0, 2 * Math.PI, false); - ctx.fill(); - }} - /> + + ); } diff --git a/frontend/src/store/actions/serviceMap.ts b/frontend/src/store/actions/serviceMap.ts index 5274eec75c..b9fa22959d 100644 --- a/frontend/src/store/actions/serviceMap.ts +++ b/frontend/src/store/actions/serviceMap.ts @@ -1,4 +1,6 @@ import api from 'api'; +import { IResourceAttribute } from 'hooks/useResourceAttribute/types'; +import { convertRawQueriesToTraceSelectedTags } from 'hooks/useResourceAttribute/utils'; import { Dispatch } from 'redux'; import { GlobalTime } from 'types/actions/globalTime'; @@ -30,16 +32,17 @@ export interface ServiceMapLoading { }; } -export const getDetailedServiceMapItems = (globalTime: GlobalTime) => async ( - dispatch: Dispatch, -): Promise => { +export const getDetailedServiceMapItems = ( + globalTime: GlobalTime, + queries: IResourceAttribute[], +) => async (dispatch: Dispatch): Promise => { const start = `${globalTime.minTime}`; const end = `${globalTime.maxTime}`; const serviceMapPayload = { start, end, - tags: [], + tags: convertRawQueriesToTraceSelectedTags(queries), }; const [dependencyGraphResponse] = await Promise.all([ api.post(`/dependency_graph`, serviceMapPayload),