mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-28 15:48:12 +00:00
203 lines
6.0 KiB
TypeScript
203 lines
6.0 KiB
TypeScript
import { useNavigateToExplorer } from 'components/CeleryTask/useNavigateToExplorer';
|
|
import { ToggleGraphProps } from 'components/Graph/types';
|
|
import { QueryParams } from 'constants/query';
|
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
|
import { handleGraphClick } from 'container/GridCardLayout/GridCard/utils';
|
|
import { useGraphClickToShowButton } from 'container/GridCardLayout/useGraphClickToShowButton';
|
|
import useNavigateToExplorerPages from 'container/GridCardLayout/useNavigateToExplorerPages';
|
|
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
|
|
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
|
import { useNotifications } from 'hooks/useNotifications';
|
|
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
|
import useUrlQuery from 'hooks/useUrlQuery';
|
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
|
import GetMinMax from 'lib/getMinMax';
|
|
import getTimeString from 'lib/getTimeString';
|
|
import {
|
|
Dispatch,
|
|
SetStateAction,
|
|
useCallback,
|
|
useEffect,
|
|
useRef,
|
|
useState,
|
|
} from 'react';
|
|
import { UseQueryResult } from 'react-query';
|
|
import { useDispatch } from 'react-redux';
|
|
import { useLocation } from 'react-router-dom';
|
|
import { UpdateTimeInterval } from 'store/actions';
|
|
import { SuccessResponse } from 'types/api';
|
|
import { Widgets } from 'types/api/dashboard/getAll';
|
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
|
import { DataSource } from 'types/common/queryBuilder';
|
|
|
|
function WidgetGraph({
|
|
selectedWidget,
|
|
queryResponse,
|
|
setRequestData,
|
|
selectedGraph,
|
|
}: WidgetGraphProps): JSX.Element {
|
|
const graphRef = useRef<HTMLDivElement>(null);
|
|
const lineChartRef = useRef<ToggleGraphProps>();
|
|
const dispatch = useDispatch();
|
|
const urlQuery = useUrlQuery();
|
|
const location = useLocation();
|
|
const { safeNavigate } = useSafeNavigate();
|
|
|
|
// Add legend state management similar to dashboard components
|
|
const [graphVisibility, setGraphVisibility] = useState<boolean[]>(
|
|
Array((queryResponse.data?.payload?.data?.result?.length || 0) + 1).fill(
|
|
true,
|
|
),
|
|
);
|
|
|
|
// Initialize graph visibility when data changes
|
|
useEffect(() => {
|
|
if (queryResponse.data?.payload?.data?.result) {
|
|
setGraphVisibility(
|
|
Array(queryResponse.data.payload.data.result.length + 1).fill(true),
|
|
);
|
|
}
|
|
}, [queryResponse.data?.payload?.data?.result]);
|
|
|
|
// Apply graph visibility when lineChartRef is available
|
|
useEffect(() => {
|
|
if (!lineChartRef.current) return;
|
|
|
|
graphVisibility.forEach((state, index) => {
|
|
lineChartRef.current?.toggleGraph(index, state);
|
|
});
|
|
}, [graphVisibility]);
|
|
|
|
const handleBackNavigation = (): void => {
|
|
const searchParams = new URLSearchParams(window.location.search);
|
|
const startTime = searchParams.get(QueryParams.startTime);
|
|
const endTime = searchParams.get(QueryParams.endTime);
|
|
const relativeTime = searchParams.get(
|
|
QueryParams.relativeTime,
|
|
) as CustomTimeType;
|
|
|
|
if (relativeTime) {
|
|
dispatch(UpdateTimeInterval(relativeTime));
|
|
} else if (startTime && endTime && startTime !== endTime) {
|
|
dispatch(
|
|
UpdateTimeInterval('custom', [
|
|
parseInt(getTimeString(startTime), 10),
|
|
parseInt(getTimeString(endTime), 10),
|
|
]),
|
|
);
|
|
}
|
|
};
|
|
|
|
const onDragSelect = useCallback(
|
|
(start: number, end: number): void => {
|
|
const startTimestamp = Math.trunc(start);
|
|
const endTimestamp = Math.trunc(end);
|
|
|
|
if (startTimestamp !== endTimestamp) {
|
|
dispatch(UpdateTimeInterval('custom', [startTimestamp, endTimestamp]));
|
|
}
|
|
|
|
const { maxTime, minTime } = GetMinMax('custom', [
|
|
startTimestamp,
|
|
endTimestamp,
|
|
]);
|
|
|
|
urlQuery.set(QueryParams.startTime, minTime.toString());
|
|
urlQuery.set(QueryParams.endTime, maxTime.toString());
|
|
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
|
safeNavigate(generatedUrl);
|
|
},
|
|
[dispatch, location.pathname, safeNavigate, urlQuery],
|
|
);
|
|
|
|
useEffect(() => {
|
|
window.addEventListener('popstate', handleBackNavigation);
|
|
|
|
return (): void => {
|
|
window.removeEventListener('popstate', handleBackNavigation);
|
|
};
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
const isDarkMode = useIsDarkMode();
|
|
|
|
// context redirection to explorer pages
|
|
const graphClick = useGraphClickToShowButton({
|
|
graphRef,
|
|
isButtonEnabled: (selectedWidget?.query?.builder?.queryData ?? []).some(
|
|
(q) =>
|
|
q.dataSource === DataSource.TRACES || q.dataSource === DataSource.LOGS,
|
|
),
|
|
buttonClassName: 'view-onclick-show-button',
|
|
});
|
|
|
|
const navigateToExplorer = useNavigateToExplorer();
|
|
const navigateToExplorerPages = useNavigateToExplorerPages();
|
|
const { notifications } = useNotifications();
|
|
|
|
const graphClickHandler = (
|
|
xValue: number,
|
|
yValue: number,
|
|
mouseX: number,
|
|
mouseY: number,
|
|
metric?: { [key: string]: string },
|
|
queryData?: { queryName: string; inFocusOrNot: boolean },
|
|
): void => {
|
|
handleGraphClick({
|
|
xValue,
|
|
yValue,
|
|
mouseX,
|
|
mouseY,
|
|
metric,
|
|
queryData,
|
|
widget: selectedWidget,
|
|
navigateToExplorerPages,
|
|
navigateToExplorer,
|
|
notifications,
|
|
graphClick,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={graphRef}
|
|
style={{
|
|
height: '100%',
|
|
width: '100%',
|
|
marginTop: '16px',
|
|
borderRadius: '3px',
|
|
border: isDarkMode
|
|
? '1px solid var(--bg-slate-500)'
|
|
: '1px solid var(--bg-vanilla-300)',
|
|
background: isDarkMode
|
|
? 'linear-gradient(0deg, rgba(171, 189, 255, 0.00) 0%, rgba(171, 189, 255, 0.00) 100%), #0B0C0E'
|
|
: 'var(--bg-vanilla-100)',
|
|
}}
|
|
>
|
|
<PanelWrapper
|
|
widget={selectedWidget}
|
|
queryResponse={queryResponse}
|
|
setRequestData={setRequestData}
|
|
onDragSelect={onDragSelect}
|
|
selectedGraph={selectedGraph}
|
|
onClickHandler={graphClickHandler}
|
|
graphVisibility={graphVisibility}
|
|
setGraphVisibility={setGraphVisibility}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface WidgetGraphProps {
|
|
selectedWidget: Widgets;
|
|
queryResponse: UseQueryResult<
|
|
SuccessResponse<MetricRangePayloadProps, unknown>,
|
|
Error
|
|
>;
|
|
setRequestData: Dispatch<SetStateAction<GetQueryResultsProps>>;
|
|
selectedGraph: PANEL_TYPES;
|
|
}
|
|
|
|
export default WidgetGraph;
|