From 06ef9ff384ec412adf591e66c43207c60d26e1ec Mon Sep 17 00:00:00 2001 From: Amlan Kumar Nandy <45410599+amlannandy@users.noreply.github.com> Date: Mon, 7 Jul 2025 23:51:06 +0700 Subject: [PATCH] fix: resolve ui full reload on auto-refresh (#8383) --- .../HostMetricTraces/HostMetricTraces.tsx | 4 +- .../HostMetricsDetail/HostMetricsDetails.tsx | 17 +++- .../HostMetricsDetail/Metrics/Metrics.tsx | 24 +++-- .../InfraMonitoringHosts/HostsList.tsx | 33 ++++++- .../HostsListControls.tsx | 4 +- .../InfraMonitoringHosts/HostsListTable.tsx | 10 +- .../__tests__/HostsListControl.test.tsx | 1 + .../__tests__/HostsListTable.test.tsx | 38 ++++++- .../ClusterDetails/ClusterDetails.tsx | 17 +++- .../Clusters/K8sClustersList.tsx | 98 +++++++++++++++---- .../DaemonSetDetails/DaemonSetDetails.tsx | 17 +++- .../DaemonSets/K8sDaemonSetsList.tsx | 98 +++++++++++++++---- .../DeploymentDetails/DeploymentDetails.tsx | 17 +++- .../Deployments/K8sDeploymentsList.tsx | 98 +++++++++++++++---- .../EntityEvents/EntityEvents.tsx | 2 +- .../EntityMetrics/EntityMetrics.tsx | 27 +++-- .../EntityTraces/EntityTraces.tsx | 4 +- .../Jobs/JobDetails/JobDetails.tsx | 17 +++- .../InfraMonitoringK8s/Jobs/K8sJobsList.tsx | 57 ++++++++++- .../InfraMonitoringK8s/K8sHeader.tsx | 4 +- .../Namespaces/K8sNamespacesList.tsx | 98 +++++++++++++++---- .../NamespaceDetails/NamespaceDetails.tsx | 17 +++- .../InfraMonitoringK8s/Nodes/K8sNodesList.tsx | 98 +++++++++++++++---- .../Nodes/NodeDetails/NodeDetails.tsx | 17 +++- .../InfraMonitoringK8s/Pods/K8sPodLists.tsx | 91 +++++++++++++---- .../Pods/PodDetails/PodDetails.tsx | 17 +++- .../StatefulSets/K8sStatefulSetsList.tsx | 98 +++++++++++++++---- .../StatefulSetDetails/StatefulSetDetails.tsx | 17 +++- .../Volumes/K8sVolumesList.tsx | 35 ++++--- .../Volumes/VolumeDetails/VolumeDetails.tsx | 17 +++- .../src/hooks/useMultiIntersectionObserver.ts | 54 ++++++++++ 31 files changed, 921 insertions(+), 225 deletions(-) create mode 100644 frontend/src/hooks/useMultiIntersectionObserver.ts diff --git a/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx b/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx index e5a75cc9b037..482e19f9b93f 100644 --- a/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx +++ b/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx @@ -194,7 +194,7 @@ function HostMetricTraces({ {!isError && traces.length > 0 && (
=> ({ diff --git a/frontend/src/components/HostMetricsDetail/HostMetricsDetails.tsx b/frontend/src/components/HostMetricsDetail/HostMetricsDetails.tsx index 28d055b2eb76..1c72ef9fa81a 100644 --- a/frontend/src/components/HostMetricsDetail/HostMetricsDetails.tsx +++ b/frontend/src/components/HostMetricsDetail/HostMetricsDetails.tsx @@ -37,7 +37,7 @@ import { ScrollText, X, } from 'lucide-react'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; import { useSearchParams } from 'react-router-dom-v5-compat'; import { AppState } from 'store/reducers'; @@ -86,8 +86,12 @@ function HostMetricsDetails({ endTime: endMs, })); + const lastSelectedInterval = useRef
{queries.map((query, idx) => ( - + {hostWidgetInfo[idx].title} {renderCardContent(query, idx)} diff --git a/frontend/src/container/InfraMonitoringHosts/HostsList.tsx b/frontend/src/container/InfraMonitoringHosts/HostsList.tsx index f67b47c7f786..269a0f9d079d 100644 --- a/frontend/src/container/InfraMonitoringHosts/HostsList.tsx +++ b/frontend/src/container/InfraMonitoringHosts/HostsList.tsx @@ -96,11 +96,41 @@ function HostsList(): JSX.Element { }; }, [pageSize, currentPage, filters, minTime, maxTime, orderBy]); + const queryKey = useMemo(() => { + if (selectedHostName) { + return [ + 'hostList', + String(pageSize), + String(currentPage), + JSON.stringify(filters), + JSON.stringify(orderBy), + ]; + } + return [ + 'hostList', + String(pageSize), + String(currentPage), + JSON.stringify(filters), + JSON.stringify(orderBy), + String(minTime), + String(maxTime), + ]; + }, [ + pageSize, + currentPage, + filters, + orderBy, + selectedHostName, + minTime, + maxTime, + ]); + const { data, isFetching, isLoading, isError } = useGetHostList( query as HostListPayload, { - queryKey: ['hostList', query], + queryKey, enabled: !!query, + keepPreviousData: true, }, ); @@ -212,6 +242,7 @@ function HostsList(): JSX.Element { void; filters: IBuilderQuery['filters']; + showAutoRefresh: boolean; }): JSX.Element { const currentQuery = initialQueriesMap[DataSource.METRICS]; const updatedCurrentQuery = useMemo( @@ -58,7 +60,7 @@ function HostsListControls({
diff --git a/frontend/src/container/InfraMonitoringHosts/HostsListTable.tsx b/frontend/src/container/InfraMonitoringHosts/HostsListTable.tsx index 5c7d3bbe17c7..513444f69e57 100644 --- a/frontend/src/container/InfraMonitoringHosts/HostsListTable.tsx +++ b/frontend/src/container/InfraMonitoringHosts/HostsListTable.tsx @@ -93,9 +93,13 @@ export default function HostsListTable({ const showHostsEmptyState = !isFetching && !isLoading && + formattedHostMetricsData.length === 0 && (!sentAnyHostMetricsData || isSendingIncorrectK8SAgentMetrics) && !filters.items.length; + const showTableLoadingState = + (isLoading || isFetching) && formattedHostMetricsData.length === 0; + if (isError) { return {data?.error || 'Something went wrong'}; } @@ -127,7 +131,7 @@ export default function HostsListTable({ ); } - if (isLoading || isFetching) { + if (showTableLoadingState) { return (
} />, }} tableLayout="fixed" diff --git a/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListControl.test.tsx b/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListControl.test.tsx index d5bad4c81f8f..be299a253ce1 100644 --- a/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListControl.test.tsx +++ b/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListControl.test.tsx @@ -28,6 +28,7 @@ describe('HostsListControls', () => { , ); diff --git a/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListTable.test.tsx b/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListTable.test.tsx index 1f71b947c51a..8736b1740d87 100644 --- a/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListTable.test.tsx +++ b/frontend/src/container/InfraMonitoringHosts/__tests__/HostsListTable.test.tsx @@ -59,13 +59,27 @@ describe('HostsListTable', () => { setPageSize: mockSetPageSize, } as any; - it('renders loading state if isLoading is true', () => { - const { container } = render(); + it('renders loading state if isLoading is true and tableData is empty', () => { + const { container } = render( + , + ); expect(container.querySelector('.hosts-list-loading-state')).toBeTruthy(); }); - it('renders loading state if isFetching is true', () => { - const { container } = render(); + it('renders loading state if isFetching is true and tableData is empty', () => { + const { container } = render( + , + ); expect(container.querySelector('.hosts-list-loading-state')).toBeTruthy(); }); @@ -75,7 +89,17 @@ describe('HostsListTable', () => { }); it('renders empty state if no hosts are found', () => { - const { container } = render(); + const { container } = render( + , + ); expect(container.querySelector(EMPTY_STATE_CONTAINER_CLASS)).toBeTruthy(); }); @@ -83,6 +107,7 @@ describe('HostsListTable', () => { const { container } = render( { data: { ...mockTableData.payload.data, sentAnyHostMetricsData: false, + hosts: [], }, }, }} @@ -102,6 +128,7 @@ describe('HostsListTable', () => { const { container } = render( { data: { ...mockTableData.payload.data, isSendingIncorrectK8SAgentMetrics: true, + hosts: [], }, }, }} diff --git a/frontend/src/container/InfraMonitoringK8s/Clusters/ClusterDetails/ClusterDetails.tsx b/frontend/src/container/InfraMonitoringK8s/Clusters/ClusterDetails/ClusterDetails.tsx index b0712c94e4d6..b528983448da 100644 --- a/frontend/src/container/InfraMonitoringK8s/Clusters/ClusterDetails/ClusterDetails.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Clusters/ClusterDetails/ClusterDetails.tsx @@ -38,7 +38,7 @@ import { ScrollText, X, } from 'lucide-react'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; import { useSearchParams } from 'react-router-dom-v5-compat'; import { AppState } from 'store/reducers'; @@ -85,8 +85,12 @@ function ClusterDetails({ endTime: endMs, })); + const lastSelectedInterval = useRef