2025-08-28 19:03:29 +05:30
|
|
|
import './LogsExplorerChart.styles.scss';
|
|
|
|
|
|
2023-06-16 13:38:39 +03:00
|
|
|
import Graph from 'components/Graph';
|
|
|
|
|
import Spinner from 'components/Spinner';
|
2024-02-14 15:18:04 +05:30
|
|
|
import { QueryParams } from 'constants/query';
|
2023-08-29 15:23:22 +03:00
|
|
|
import { themeColors } from 'constants/theme';
|
2025-02-14 08:24:49 +04:30
|
|
|
import { useSafeNavigate } from 'hooks/useSafeNavigate';
|
2024-02-14 15:18:04 +05:30
|
|
|
import useUrlQuery from 'hooks/useUrlQuery';
|
2023-07-06 14:22:44 +03:00
|
|
|
import getChartData, { GetChartDataProps } from 'lib/getChartData';
|
2024-02-14 15:18:04 +05:30
|
|
|
import GetMinMax from 'lib/getMinMax';
|
2023-07-06 14:22:44 +03:00
|
|
|
import { colors } from 'lib/getRandomColor';
|
2025-02-14 08:24:49 +04:30
|
|
|
import { memo, useCallback, useMemo } from 'react';
|
2025-07-29 17:00:34 +04:30
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
2024-02-14 15:18:04 +05:30
|
|
|
import { useLocation } from 'react-router-dom';
|
|
|
|
|
import { UpdateTimeInterval } from 'store/actions';
|
2025-07-29 17:00:34 +04:30
|
|
|
import { AppState } from 'store/reducers';
|
|
|
|
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
2023-06-16 13:38:39 +03:00
|
|
|
|
2023-07-06 14:22:44 +03:00
|
|
|
import { LogsExplorerChartProps } from './LogsExplorerChart.interfaces';
|
2024-09-13 13:47:08 +05:30
|
|
|
import { getColorsForSeverityLabels } from './utils';
|
2023-06-16 13:38:39 +03:00
|
|
|
|
2023-07-06 14:22:44 +03:00
|
|
|
function LogsExplorerChart({
|
|
|
|
|
data,
|
|
|
|
|
isLoading,
|
2023-08-29 15:23:22 +03:00
|
|
|
isLabelEnabled = true,
|
|
|
|
|
className,
|
2024-09-13 13:47:08 +05:30
|
|
|
isLogsExplorerViews = false,
|
2023-07-06 14:22:44 +03:00
|
|
|
}: LogsExplorerChartProps): JSX.Element {
|
2024-02-14 15:18:04 +05:30
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const urlQuery = useUrlQuery();
|
|
|
|
|
const location = useLocation();
|
2025-02-14 08:24:49 +04:30
|
|
|
const { safeNavigate } = useSafeNavigate();
|
2025-07-29 17:00:34 +04:30
|
|
|
|
|
|
|
|
// Access global time state for min/max range
|
|
|
|
|
const { minTime, maxTime } = useSelector<AppState, GlobalReducer>(
|
|
|
|
|
(state) => state.globalTime,
|
|
|
|
|
);
|
2023-08-29 15:23:22 +03:00
|
|
|
const handleCreateDatasets: Required<GetChartDataProps>['createDataset'] = useCallback(
|
|
|
|
|
(element, index, allLabels) => ({
|
|
|
|
|
data: element,
|
2024-09-13 13:47:08 +05:30
|
|
|
backgroundColor: isLogsExplorerViews
|
|
|
|
|
? getColorsForSeverityLabels(allLabels[index], index)
|
|
|
|
|
: colors[index % colors.length] || themeColors.red,
|
|
|
|
|
borderColor: isLogsExplorerViews
|
|
|
|
|
? getColorsForSeverityLabels(allLabels[index], index)
|
|
|
|
|
: colors[index % colors.length] || themeColors.red,
|
2023-08-29 15:23:22 +03:00
|
|
|
...(isLabelEnabled
|
|
|
|
|
? {
|
|
|
|
|
label: allLabels[index],
|
|
|
|
|
}
|
|
|
|
|
: {}),
|
|
|
|
|
}),
|
2024-09-13 13:47:08 +05:30
|
|
|
[isLabelEnabled, isLogsExplorerViews],
|
2023-08-29 15:23:22 +03:00
|
|
|
);
|
2023-07-06 14:22:44 +03:00
|
|
|
|
2024-02-14 15:18:04 +05:30
|
|
|
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());
|
2025-02-14 08:24:49 +04:30
|
|
|
urlQuery.delete(QueryParams.relativeTime);
|
2025-06-03 15:27:39 +05:30
|
|
|
// Remove Hidden Filters from URL query parameters on time change
|
|
|
|
|
urlQuery.delete(QueryParams.activeLogId);
|
2024-02-14 15:18:04 +05:30
|
|
|
const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
|
2025-02-14 08:24:49 +04:30
|
|
|
safeNavigate(generatedUrl);
|
2024-02-14 15:18:04 +05:30
|
|
|
},
|
2025-02-14 08:24:49 +04:30
|
|
|
[dispatch, location.pathname, safeNavigate, urlQuery],
|
2024-02-14 15:18:04 +05:30
|
|
|
);
|
|
|
|
|
|
2023-07-06 14:22:44 +03:00
|
|
|
const graphData = useMemo(
|
|
|
|
|
() =>
|
|
|
|
|
getChartData({
|
|
|
|
|
queryData: [
|
|
|
|
|
{
|
|
|
|
|
queryData: data,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
createDataset: handleCreateDatasets,
|
|
|
|
|
}),
|
2023-08-29 15:23:22 +03:00
|
|
|
[data, handleCreateDatasets],
|
2023-06-16 13:38:39 +03:00
|
|
|
);
|
|
|
|
|
|
2025-07-29 17:00:34 +04:30
|
|
|
// Convert nanosecond timestamps to milliseconds for Chart.js
|
|
|
|
|
const { chartMinTime, chartMaxTime } = useMemo(
|
|
|
|
|
() => ({
|
|
|
|
|
chartMinTime: minTime ? Math.floor(minTime / 1e6) : undefined,
|
|
|
|
|
chartMaxTime: maxTime ? Math.floor(maxTime / 1e6) : undefined,
|
|
|
|
|
}),
|
|
|
|
|
[minTime, maxTime],
|
|
|
|
|
);
|
|
|
|
|
|
2023-06-16 13:38:39 +03:00
|
|
|
return (
|
2025-08-28 19:03:29 +05:30
|
|
|
<div className={`${className} logs-frequency-chart-container`}>
|
2023-07-06 14:22:44 +03:00
|
|
|
{isLoading ? (
|
2025-08-28 19:03:29 +05:30
|
|
|
<div className="logs-frequency-chart-loading">
|
|
|
|
|
<Spinner size="default" height="100%" />
|
|
|
|
|
</div>
|
2023-06-16 13:38:39 +03:00
|
|
|
) : (
|
2024-02-14 15:18:04 +05:30
|
|
|
<Graph
|
|
|
|
|
name="logsExplorerChart"
|
|
|
|
|
data={graphData.data}
|
2024-09-13 13:47:08 +05:30
|
|
|
isStacked={isLogsExplorerViews}
|
2024-02-14 15:18:04 +05:30
|
|
|
type="bar"
|
|
|
|
|
animate
|
|
|
|
|
onDragSelect={onDragSelect}
|
2025-07-29 17:00:34 +04:30
|
|
|
minTime={chartMinTime}
|
|
|
|
|
maxTime={chartMaxTime}
|
2024-02-14 15:18:04 +05:30
|
|
|
/>
|
2023-06-16 13:38:39 +03:00
|
|
|
)}
|
2025-08-28 19:03:29 +05:30
|
|
|
</div>
|
2023-06-16 13:38:39 +03:00
|
|
|
);
|
|
|
|
|
}
|
2023-06-23 11:19:53 +03:00
|
|
|
|
|
|
|
|
export default memo(LogsExplorerChart);
|