Compare commits
21 Commits
main
...
perf/panel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18e856f62c | ||
|
|
c0bd545e26 | ||
|
|
346be7b7ba | ||
|
|
10176e3128 | ||
|
|
a6832d6ed0 | ||
|
|
5504e90620 | ||
|
|
19cffa0165 | ||
|
|
4dc4a0b95e | ||
|
|
2462f551be | ||
|
|
78ab80d294 | ||
|
|
d285b90f09 | ||
|
|
08e756cf5d | ||
|
|
42c1ddda39 | ||
|
|
efb85fc205 | ||
|
|
0e972257db | ||
|
|
f8144e3a1d | ||
|
|
02a8a11976 | ||
|
|
4a351e5280 | ||
|
|
311257a518 | ||
|
|
d5c665a72a | ||
|
|
0d6c8785d9 |
@@ -132,34 +132,117 @@ function CeleryTaskBar({
|
||||
[selectedFilters, celerySuccessStateData],
|
||||
);
|
||||
|
||||
const onGraphClick = (
|
||||
widgetData: Widgets,
|
||||
xValue: number,
|
||||
_yValue: number,
|
||||
_mouseX: number,
|
||||
_mouseY: number,
|
||||
data?: {
|
||||
[key: string]: string;
|
||||
const onGraphClick = useCallback(
|
||||
(
|
||||
widgetData: Widgets,
|
||||
xValue: number,
|
||||
_yValue: number,
|
||||
_mouseX: number,
|
||||
_mouseY: number,
|
||||
data?: {
|
||||
[key: string]: string;
|
||||
},
|
||||
): void => {
|
||||
const { start, end } = getStartAndEndTimesInMilliseconds(xValue);
|
||||
|
||||
// Extract entity and value from data
|
||||
const [firstDataPoint] = Object.entries(data || {});
|
||||
const [entity, value] = (firstDataPoint || ([] as unknown)) as [
|
||||
string,
|
||||
string,
|
||||
];
|
||||
|
||||
if (!isEmpty(entity) || !isEmpty(value)) {
|
||||
onClick?.({
|
||||
entity,
|
||||
value,
|
||||
timeRange: [start, end],
|
||||
widgetData,
|
||||
});
|
||||
}
|
||||
},
|
||||
): void => {
|
||||
const { start, end } = getStartAndEndTimesInMilliseconds(xValue);
|
||||
[onClick],
|
||||
);
|
||||
|
||||
// Extract entity and value from data
|
||||
const [firstDataPoint] = Object.entries(data || {});
|
||||
const [entity, value] = (firstDataPoint || ([] as unknown)) as [
|
||||
string,
|
||||
string,
|
||||
];
|
||||
const onAllStateClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data?: any,
|
||||
): void => {
|
||||
onGraphClick(
|
||||
celerySlowestTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClick],
|
||||
);
|
||||
|
||||
if (!isEmpty(entity) || !isEmpty(value)) {
|
||||
onClick?.({
|
||||
entity,
|
||||
value,
|
||||
timeRange: [start, end],
|
||||
widgetData,
|
||||
});
|
||||
}
|
||||
};
|
||||
const onFailedStateClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data?: any,
|
||||
): void => {
|
||||
onGraphClick(
|
||||
celeryFailedTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClick],
|
||||
);
|
||||
|
||||
const onRetryStateClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data?: any,
|
||||
): void => {
|
||||
onGraphClick(
|
||||
celeryRetryTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClick],
|
||||
);
|
||||
|
||||
const onSuccessStateClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data?: any,
|
||||
): void => {
|
||||
onGraphClick(
|
||||
celerySuccessTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClick],
|
||||
);
|
||||
|
||||
const { getCustomSeries } = useGetGraphCustomSeries({
|
||||
isDarkMode,
|
||||
@@ -185,16 +268,7 @@ function CeleryTaskBar({
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): void =>
|
||||
onGraphClick(
|
||||
celerySlowestTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
)
|
||||
}
|
||||
onClickHandler={onAllStateClick}
|
||||
customSeries={getCustomSeries}
|
||||
dataAvailable={checkIfDataExists}
|
||||
/>
|
||||
@@ -205,16 +279,7 @@ function CeleryTaskBar({
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): void =>
|
||||
onGraphClick(
|
||||
celeryFailedTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
)
|
||||
}
|
||||
onClickHandler={onFailedStateClick}
|
||||
customSeries={getCustomSeries}
|
||||
/>
|
||||
)}
|
||||
@@ -224,16 +289,7 @@ function CeleryTaskBar({
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): void =>
|
||||
onGraphClick(
|
||||
celeryRetryTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
)
|
||||
}
|
||||
onClickHandler={onRetryStateClick}
|
||||
customSeries={getCustomSeries}
|
||||
/>
|
||||
)}
|
||||
@@ -243,16 +299,7 @@ function CeleryTaskBar({
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onDragSelect={onDragSelect}
|
||||
isQueryEnabled={queryEnabled}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): void =>
|
||||
onGraphClick(
|
||||
celerySuccessTasksTableWidgetData,
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
data,
|
||||
)
|
||||
}
|
||||
onClickHandler={onSuccessStateClick}
|
||||
customSeries={getCustomSeries}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
@@ -76,6 +77,7 @@ function WidgetGraphComponent({
|
||||
const isFullViewOpen = params.get(QueryParams.expandedWidgetId) === widget.id;
|
||||
|
||||
const lineChartRef = useRef<ToggleGraphProps>();
|
||||
|
||||
const [graphVisibility, setGraphVisibility] = useState<boolean[]>(
|
||||
Array(queryResponse.data?.payload?.data?.result?.length || 0).fill(true),
|
||||
);
|
||||
@@ -110,7 +112,7 @@ function WidgetGraphComponent({
|
||||
|
||||
const updateDashboardMutation = useUpdateDashboard();
|
||||
|
||||
const onDeleteHandler = (): void => {
|
||||
const onDeleteHandler = useCallback((): void => {
|
||||
if (!selectedDashboard) return;
|
||||
|
||||
const updatedWidgets = selectedDashboard?.data?.widgets?.filter(
|
||||
@@ -138,9 +140,15 @@ function WidgetGraphComponent({
|
||||
setDeleteModal(false);
|
||||
},
|
||||
});
|
||||
};
|
||||
}, [
|
||||
selectedDashboard,
|
||||
widget.id,
|
||||
updateDashboardMutation,
|
||||
setLayouts,
|
||||
setSelectedDashboard,
|
||||
]);
|
||||
|
||||
const onCloneHandler = async (): Promise<void> => {
|
||||
const onCloneHandler = useCallback(async (): Promise<void> => {
|
||||
if (!selectedDashboard) return;
|
||||
|
||||
const uuid = v4();
|
||||
@@ -204,9 +212,18 @@ function WidgetGraphComponent({
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
}, [
|
||||
selectedDashboard,
|
||||
widget,
|
||||
updateDashboardMutation,
|
||||
setLayouts,
|
||||
setSelectedDashboard,
|
||||
notifications,
|
||||
safeNavigate,
|
||||
pathname,
|
||||
]);
|
||||
|
||||
const handleOnView = (): void => {
|
||||
const handleOnView = useCallback((): void => {
|
||||
const queryParams = {
|
||||
[QueryParams.expandedWidgetId]: widget.id,
|
||||
};
|
||||
@@ -225,17 +242,17 @@ function WidgetGraphComponent({
|
||||
pathname,
|
||||
search: newSearch,
|
||||
});
|
||||
};
|
||||
}, [widget.id, search, pathname, safeNavigate]);
|
||||
|
||||
const handleOnDelete = (): void => {
|
||||
const handleOnDelete = useCallback((): void => {
|
||||
onToggleModal(setDeleteModal);
|
||||
};
|
||||
}, [onToggleModal]);
|
||||
|
||||
const onDeleteModelHandler = (): void => {
|
||||
const onDeleteModelHandler = useCallback((): void => {
|
||||
onToggleModal(setDeleteModal);
|
||||
};
|
||||
}, [onToggleModal]);
|
||||
|
||||
const onToggleModelHandler = (): void => {
|
||||
const onToggleModelHandler = useCallback((): void => {
|
||||
const existingSearchParams = new URLSearchParams(search);
|
||||
existingSearchParams.delete(QueryParams.expandedWidgetId);
|
||||
existingSearchParams.delete(QueryParams.compositeQuery);
|
||||
@@ -254,63 +271,84 @@ function WidgetGraphComponent({
|
||||
pathname,
|
||||
search: createQueryParams(updatedQueryParams),
|
||||
});
|
||||
};
|
||||
}, [search, queryResponse.data?.payload, widget.id, pathname, safeNavigate]);
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState<string>('');
|
||||
|
||||
// Memoize the isButtonEnabled value to prevent recalculation
|
||||
const isGraphClickButtonEnabled = useMemo(
|
||||
() =>
|
||||
(widget?.query?.builder?.queryData &&
|
||||
Array.isArray(widget.query.builder.queryData)
|
||||
? widget.query.builder.queryData
|
||||
: []
|
||||
).some(
|
||||
(q) =>
|
||||
q.dataSource === DataSource.TRACES || q.dataSource === DataSource.LOGS,
|
||||
),
|
||||
[widget?.query?.builder?.queryData],
|
||||
);
|
||||
|
||||
const graphClick = useGraphClickToShowButton({
|
||||
graphRef: currentGraphRef?.current ? currentGraphRef : graphRef,
|
||||
isButtonEnabled: (widget?.query?.builder?.queryData &&
|
||||
Array.isArray(widget.query.builder.queryData)
|
||||
? widget.query.builder.queryData
|
||||
: []
|
||||
).some(
|
||||
(q) =>
|
||||
q.dataSource === DataSource.TRACES || q.dataSource === DataSource.LOGS,
|
||||
),
|
||||
isButtonEnabled: isGraphClickButtonEnabled,
|
||||
buttonClassName: 'view-onclick-show-button',
|
||||
});
|
||||
|
||||
const navigateToExplorer = useNavigateToExplorer();
|
||||
|
||||
const graphClickHandler = (
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
metric?: { [key: string]: string },
|
||||
queryData?: { queryName: string; inFocusOrNot: boolean },
|
||||
): void => {
|
||||
const customTracesTimeRange = getCustomTimeRangeWindowSweepInMS(
|
||||
const graphClickHandler = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
metric?: { [key: string]: string },
|
||||
queryData?: { queryName: string; inFocusOrNot: boolean },
|
||||
): void => {
|
||||
const customTracesTimeRange = getCustomTimeRangeWindowSweepInMS(
|
||||
customTimeRangeWindowForCoRelation,
|
||||
);
|
||||
const { start, end } = getStartAndEndTimesInMilliseconds(
|
||||
xValue,
|
||||
customTracesTimeRange,
|
||||
);
|
||||
handleGraphClick({
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
metric,
|
||||
queryData,
|
||||
widget,
|
||||
navigateToExplorerPages,
|
||||
navigateToExplorer,
|
||||
notifications,
|
||||
graphClick,
|
||||
...(customTimeRangeWindowForCoRelation
|
||||
? { customTracesTimeRange: { start, end } }
|
||||
: {}),
|
||||
});
|
||||
},
|
||||
[
|
||||
customTimeRangeWindowForCoRelation,
|
||||
);
|
||||
const { start, end } = getStartAndEndTimesInMilliseconds(
|
||||
xValue,
|
||||
customTracesTimeRange,
|
||||
);
|
||||
handleGraphClick({
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
metric,
|
||||
queryData,
|
||||
widget,
|
||||
navigateToExplorerPages,
|
||||
navigateToExplorer,
|
||||
notifications,
|
||||
graphClick,
|
||||
...(customTimeRangeWindowForCoRelation
|
||||
? { customTracesTimeRange: { start, end } }
|
||||
: {}),
|
||||
});
|
||||
};
|
||||
],
|
||||
);
|
||||
|
||||
const { truncatedText, fullText } = useGetResolvedText({
|
||||
text: widget.title as string,
|
||||
maxLength: 100,
|
||||
});
|
||||
|
||||
// Use the provided onClickHandler if available, otherwise use the default graphClickHandler
|
||||
// Both should be stable references due to useCallback
|
||||
const clickHandler = onClickHandler ?? graphClickHandler;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -366,7 +404,7 @@ function WidgetGraphComponent({
|
||||
yAxisUnit={widget.yAxisUnit}
|
||||
onToggleModelHandler={onToggleModelHandler}
|
||||
tableProcessedDataRef={tableProcessedDataRef}
|
||||
onClickHandler={onClickHandler ?? graphClickHandler}
|
||||
onClickHandler={clickHandler}
|
||||
customOnDragSelect={customOnDragSelect}
|
||||
setCurrentGraphRef={setCurrentGraphRef}
|
||||
enableDrillDown={
|
||||
@@ -416,7 +454,7 @@ function WidgetGraphComponent({
|
||||
setRequestData={setRequestData}
|
||||
setGraphVisibility={setGraphVisibility}
|
||||
graphVisibility={graphVisibility}
|
||||
onClickHandler={onClickHandler ?? graphClickHandler}
|
||||
onClickHandler={clickHandler}
|
||||
onDragSelect={onDragSelect}
|
||||
tableProcessedDataRef={tableProcessedDataRef}
|
||||
customTooltipElement={customTooltipElement}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems
|
||||
import { getDashboardVariables } from 'lib/dashbaordVariables/getDashboardVariables';
|
||||
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
|
||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { useMutation } from 'react-query';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
@@ -46,6 +46,11 @@ function useUpdatedQuery(): UseUpdatedQueryResult {
|
||||
[selectedDashboard],
|
||||
);
|
||||
|
||||
// Use ref to access latest mutateAsync without recreating the callback
|
||||
// queryRangeMutation object recreates on every render, but mutateAsync is stable
|
||||
const mutateAsyncRef = useRef(queryRangeMutation.mutateAsync);
|
||||
mutateAsyncRef.current = queryRangeMutation.mutateAsync;
|
||||
|
||||
const getUpdatedQuery = useCallback(
|
||||
async ({
|
||||
widgetConfig,
|
||||
@@ -63,12 +68,12 @@ function useUpdatedQuery(): UseUpdatedQueryResult {
|
||||
});
|
||||
|
||||
// Execute query and process results
|
||||
const queryResult = await queryRangeMutation.mutateAsync(queryPayload);
|
||||
const queryResult = await mutateAsyncRef.current(queryPayload);
|
||||
|
||||
// Map query data from API response
|
||||
return mapQueryDataFromApi(queryResult.data.compositeQuery);
|
||||
},
|
||||
[dynamicVariables, globalSelectedInterval, queryRangeMutation],
|
||||
[dynamicVariables, globalSelectedInterval],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -238,6 +238,86 @@ function External(): JSX.Element {
|
||||
setSelectedData,
|
||||
);
|
||||
|
||||
const onErrorPercentageClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data: any,
|
||||
): void => {
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_error_percentage',
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClickHandler],
|
||||
);
|
||||
|
||||
const onDurationClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data: any,
|
||||
): void => {
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_duration',
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClickHandler],
|
||||
);
|
||||
|
||||
const onRPSByAddressClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data: any,
|
||||
): void => {
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_rps_by_address',
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClickHandler],
|
||||
);
|
||||
|
||||
const onDurationByAddressClick = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
yValue: number,
|
||||
mouseX: number,
|
||||
mouseY: number,
|
||||
data: any,
|
||||
): void => {
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_duration_by_address',
|
||||
data,
|
||||
);
|
||||
},
|
||||
[onGraphClickHandler],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Row gutter={24}>
|
||||
@@ -266,16 +346,7 @@ function External(): JSX.Element {
|
||||
<Graph
|
||||
headerMenuList={MENU_ITEMS}
|
||||
widget={externalCallErrorWidget}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): void => {
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_error_percentage',
|
||||
data,
|
||||
);
|
||||
}}
|
||||
onClickHandler={onErrorPercentageClick}
|
||||
onDragSelect={onDragSelect}
|
||||
version={ENTITY_VERSION_V4}
|
||||
/>
|
||||
@@ -309,16 +380,7 @@ function External(): JSX.Element {
|
||||
<Graph
|
||||
headerMenuList={MENU_ITEMS}
|
||||
widget={externalCallDurationWidget}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): void => {
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_duration',
|
||||
data,
|
||||
);
|
||||
}}
|
||||
onClickHandler={onDurationClick}
|
||||
onDragSelect={onDragSelect}
|
||||
version={ENTITY_VERSION_V4}
|
||||
/>
|
||||
@@ -353,16 +415,7 @@ function External(): JSX.Element {
|
||||
<Graph
|
||||
widget={externalCallRPSWidget}
|
||||
headerMenuList={MENU_ITEMS}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): Promise<void> =>
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_rps_by_address',
|
||||
data,
|
||||
)
|
||||
}
|
||||
onClickHandler={onRPSByAddressClick}
|
||||
onDragSelect={onDragSelect}
|
||||
version={ENTITY_VERSION_V4}
|
||||
/>
|
||||
@@ -396,16 +449,7 @@ function External(): JSX.Element {
|
||||
<Graph
|
||||
widget={externalCallDurationAddressWidget}
|
||||
headerMenuList={MENU_ITEMS}
|
||||
onClickHandler={(xValue, yValue, mouseX, mouseY, data): void => {
|
||||
onGraphClickHandler(
|
||||
xValue,
|
||||
yValue,
|
||||
mouseX,
|
||||
mouseY,
|
||||
'external_call_duration_by_address',
|
||||
data,
|
||||
);
|
||||
}}
|
||||
onClickHandler={onDurationByAddressClick}
|
||||
onDragSelect={onDragSelect}
|
||||
version={ENTITY_VERSION_V4}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import isEqual from 'lodash-es/isEqual';
|
||||
import { FC, memo } from 'react';
|
||||
|
||||
import { PanelTypeVsPanelWrapper } from './constants';
|
||||
import { PanelWrapperProps } from './panelWrapper.types';
|
||||
@@ -55,4 +56,36 @@ function PanelWrapper({
|
||||
);
|
||||
}
|
||||
|
||||
export default PanelWrapper;
|
||||
function arePropsEqual(
|
||||
prevProps: PanelWrapperProps,
|
||||
nextProps: PanelWrapperProps,
|
||||
): boolean {
|
||||
// Destructure to separate props that need deep comparison from the rest
|
||||
const {
|
||||
widget: prevWidget,
|
||||
queryResponse: prevQueryResponse,
|
||||
...prevRest
|
||||
} = prevProps;
|
||||
const {
|
||||
widget: nextWidget,
|
||||
queryResponse: nextQueryResponse,
|
||||
...nextRest
|
||||
} = nextProps;
|
||||
|
||||
// Shallow equality check for all other props (primitives, functions, refs, arrays)
|
||||
const restKeys = Object.keys(prevRest) as Array<
|
||||
keyof Omit<PanelWrapperProps, 'widget' | 'queryResponse'>
|
||||
>;
|
||||
|
||||
if (restKeys.some((key) => prevRest[key] !== nextRest[key])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deep equality only for widget config and query response data payload
|
||||
return (
|
||||
isEqual(prevWidget, nextWidget) &&
|
||||
isEqual(prevQueryResponse.data?.payload, nextQueryResponse.data?.payload)
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(PanelWrapper, arePropsEqual);
|
||||
|
||||
@@ -132,11 +132,21 @@ function UplotPanelWrapper({
|
||||
[selectedGraph, widget?.panelTypes, widget?.stackedBarChart],
|
||||
);
|
||||
|
||||
const chartData = getUPlotChartData(
|
||||
queryResponse?.data?.payload,
|
||||
widget.fillSpans,
|
||||
stackedBarChart,
|
||||
hiddenGraph,
|
||||
// Memoize chartData to prevent unnecessary recalculations
|
||||
const chartData = useMemo(
|
||||
() =>
|
||||
getUPlotChartData(
|
||||
queryResponse?.data?.payload,
|
||||
widget.fillSpans,
|
||||
stackedBarChart,
|
||||
hiddenGraph,
|
||||
),
|
||||
[
|
||||
queryResponse?.data?.payload,
|
||||
widget.fillSpans,
|
||||
stackedBarChart,
|
||||
hiddenGraph,
|
||||
],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -77,6 +77,20 @@ function MessagingQueuesGraph(): JSX.Element {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onClickHandler = useCallback(
|
||||
(
|
||||
xValue: number,
|
||||
_yValue: number,
|
||||
_mouseX: number,
|
||||
_mouseY: number,
|
||||
data?: any,
|
||||
): void => {
|
||||
setSelectedTimelineQuery(urlQuery, xValue, location, history, data);
|
||||
},
|
||||
[urlQuery, location, history],
|
||||
);
|
||||
|
||||
return (
|
||||
<Card
|
||||
isDarkMode={isDarkMode}
|
||||
@@ -86,9 +100,7 @@ function MessagingQueuesGraph(): JSX.Element {
|
||||
<GridCard
|
||||
widget={widgetData}
|
||||
headerMenuList={[...ViewMenuAction]}
|
||||
onClickHandler={(xValue, _yValue, _mouseX, _mouseY, data): void => {
|
||||
setSelectedTimelineQuery(urlQuery, xValue, location, history, data);
|
||||
}}
|
||||
onClickHandler={onClickHandler}
|
||||
onDragSelect={onDragSelect}
|
||||
customTooltipElement={messagingQueueCustomTooltipText()}
|
||||
dataAvailable={checkIfDataExists}
|
||||
|
||||
Reference in New Issue
Block a user