This is an automated email from the ASF dual-hosted git repository.

arafat2198 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 428cb5609b3 HDDS-13542. Separate out the API calls for Overview page 
(#9033)
428cb5609b3 is described below

commit 428cb5609b350ee5ee7a205e9180c29c205aab4d
Author: Abhishek Pal <[email protected]>
AuthorDate: Wed Sep 17 20:17:34 2025 +0530

    HDDS-13542. Separate out the API calls for Overview page (#9033)
---
 .../webapps/recon/ozone-recon-web/src/app.less     |   6 +
 .../{errorBoundary => errors}/errorBoundary.tsx    |   0
 .../errors/errorCard.tsx}                          |  41 ++-
 .../components/overviewCard/overviewSimpleCard.tsx |  17 +-
 .../overviewCard/overviewStorageCard.tsx           |  10 +-
 .../overviewCard/overviewSummaryCard.tsx           |  11 +-
 .../tables/insights/containerMismatchTable.tsx     |   2 +-
 .../tables/insights/deletePendingDirsTable.tsx     |   2 +-
 .../tables/insights/deletePendingKeysTable.tsx     |   2 +-
 .../tables/insights/deletedContainerKeysTable.tsx  |   2 +-
 .../components/tables/insights/openKeysTable.tsx   |   2 +-
 .../src/v2/constants/overview.constants.tsx        |  50 +++
 .../src/v2/hooks/useAPIData.hook.ts                | 187 +++++++++++
 .../src/v2/hooks/useAutoReload.hook.tsx            |  89 ++++++
 .../hooks/{debounce.hook.tsx => useDebounce.tsx}   |   0
 .../src/v2/pages/buckets/buckets.tsx               |   2 +-
 .../src/v2/pages/containers/containers.tsx         |   2 +-
 .../src/v2/pages/datanodes/datanodes.tsx           |   2 +-
 .../src/v2/pages/overview/overview.tsx             | 347 ++++++++-------------
 .../src/v2/pages/pipelines/pipelines.tsx           |   2 +-
 .../src/v2/pages/volumes/volumes.tsx               |   2 +-
 .../ozone-recon-web/src/v2/types/overview.types.ts |  37 +--
 22 files changed, 548 insertions(+), 267 deletions(-)

diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.less
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.less
index 44f53fa9d47..6819ff701e6 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.less
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/app.less
@@ -169,4 +169,10 @@ body {
 .data-container {
   padding: 24px;
   height: 80vh;
+}
+
+#error-icon {
+  font-size: 24px;
+  width: 100%;
+  color: #5A656D;
 }
\ No newline at end of file
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/errorBoundary/errorBoundary.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/errors/errorBoundary.tsx
similarity index 100%
rename from 
hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/errorBoundary/errorBoundary.tsx
rename to 
hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/errors/errorBoundary.tsx
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/debounce.hook.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/errors/errorCard.tsx
similarity index 51%
copy from 
hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/debounce.hook.tsx
copy to 
hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/errors/errorCard.tsx
index e66dbd5679b..b904673a93d 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/debounce.hook.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/errors/errorCard.tsx
@@ -16,20 +16,37 @@
  * limitations under the License.
  */
 
+
 import React from 'react';
+import { DisconnectOutlined } from "@ant-design/icons"
+import { Card } from 'antd';
 
-export function useDebounce<T>(value: T, timeout: number): T {
-  const [debounceValue, setDebounceValue] = React.useState<T>(value);
+type ErrorCardProps = {
+  title: string;
+  compact?: boolean;
+};
 
-  React.useEffect(() => {
-    const timeoutHandler = setTimeout(() => {
-      setDebounceValue(value);
-    }, timeout);
+// ------------- Styles -------------- //
+const cardHeadStyle: React.CSSProperties = { fontSize: '14px' };
+const compactCardBodyStyle: React.CSSProperties = {
+  padding: '24px',
+  justifyContent: 'space-between'
+}
+const cardBodyStyle: React.CSSProperties = {
+  padding: '80px'
+}
 
-    return () => {
-      clearTimeout(timeoutHandler);
-    }
-  }, [value, timeout]); // Need to set new timeout anytime the value or 
timeout duration changes
+const ErrorCard: React.FC<ErrorCardProps> = ({ title, compact }) => {
+  return (
+    <Card
+      size='small'
+      title={title}
+      headStyle={cardHeadStyle}
+      bodyStyle={(compact) ? compactCardBodyStyle : cardBodyStyle}
+      data-testid={`error-${title}`}>
+      <DisconnectOutlined id="error-icon" />
+    </Card>
+  )
+};
 
-  return debounceValue;
-}
+export default ErrorCard;
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSimpleCard.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSimpleCard.tsx
index 2269ad9663a..5971934381e 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSimpleCard.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSimpleCard.tsx
@@ -31,6 +31,7 @@ import {
   QuestionCircleOutlined
 } from '@ant-design/icons';
 import { numberWithCommas } from '@/utils/common';
+import ErrorCard from '@/v2/components/errors/errorCard';
 
 
 // ------------- Types -------------- //
@@ -40,11 +41,12 @@ type IconOptions = {
 
 type OverviewCardProps = {
   icon: string;
-  data: number | React.ReactElement;
+  data: number;
   title: string;
   hoverable?: boolean;
   loading?: boolean;
   linkToUrl?: string;
+  error?: string | null;
 }
 
 // ------------- Styles -------------- //
@@ -109,9 +111,14 @@ const OverviewSimpleCard: React.FC<OverviewCardProps> = ({
   title = '',
   hoverable = false,
   loading = false,
-  linkToUrl = ''
+  linkToUrl = '',
+  error
 }) => {
 
+  if (error) {
+    return <ErrorCard title={title} compact={true}/>
+  }
+
   const titleElement = (linkToUrl)
     ? (
       <div className='card-title-div'>
@@ -122,7 +129,7 @@ const OverviewSimpleCard: React.FC<OverviewCardProps> = ({
           View More
         </Link>
       </div>)
-    : title
+    : title;
 
   return (
     <Card
@@ -144,6 +151,6 @@ const OverviewSimpleCard: React.FC<OverviewCardProps> = ({
       </Row>
     </Card>
   );
-}
+};
 
-export default OverviewSimpleCard;
\ No newline at end of file
+export default OverviewSimpleCard;
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewStorageCard.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewStorageCard.tsx
index 2272f2ca01d..ce9287b3db8 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewStorageCard.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewStorageCard.tsx
@@ -24,11 +24,14 @@ import EChart from '@/v2/components/eChart/eChart';
 import OverviewCardWrapper from 
'@/v2/components/overviewCard/overviewCardWrapper';
 
 import { StorageReport } from '@/v2/types/overview.types';
+import ErrorMessage from '@/v2/components/errors/errorCard';
+import ErrorCard from '@/v2/components/errors/errorCard';
 
 // ------------- Types -------------- //
 type OverviewStorageCardProps = {
   loading?: boolean;
   storageReport: StorageReport;
+  error?: string | null;
 }
 
 const size = filesize.partial({ round: 1 });
@@ -73,9 +76,14 @@ const OverviewStorageCard: 
React.FC<OverviewStorageCardProps> = ({
     used: 0,
     remaining: 0,
     committed: 0
-  }
+  },
+  error
 }) => {
 
+  if (error) {
+    return <ErrorCard title='Cluster Capacity' />
+  }
+
   const {
     ozoneUsedPercentage,
     nonOzoneUsedPercentage,
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSummaryCard.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSummaryCard.tsx
index 8736b3e0d29..9214c456b6c 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSummaryCard.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/overviewCard/overviewSummaryCard.tsx
@@ -21,6 +21,8 @@ import { Card, Row, Table } from 'antd';
 
 import { ColumnType } from 'antd/es/table';
 import { Link } from 'react-router-dom';
+import ErrorMessage from '@/v2/components/errors/errorCard';
+import ErrorCard from '@/v2/components/errors/errorCard';
 
 // ------------- Types -------------- //
 type TableData = {
@@ -40,6 +42,7 @@ type OverviewTableCardProps = {
   linkToUrl?: string;
   showHeader?: boolean;
   state?: Record<string, any>;
+  error?: string | null;
 }
 
 // ------------- Styles -------------- //
@@ -65,8 +68,14 @@ const OverviewSummaryCard: React.FC<OverviewTableCardProps> 
= ({
   tableData = [],
   linkToUrl = '',
   showHeader = false,
-  state
+  state,
+  error
 }) => {
+
+  if (error) {
+    return <ErrorCard title={title} />;
+  }
+
   const titleElement = (linkToUrl)
     ? (
       <div className='card-title-div'>
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/containerMismatchTable.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/containerMismatchTable.tsx
index 818eca37f8e..565acde6db7 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/containerMismatchTable.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/containerMismatchTable.tsx
@@ -39,7 +39,7 @@ import Search from '@/v2/components/search/search';
 import SingleSelect, { Option } from '@/v2/components/select/singleSelect';
 import { showDataFetchError } from '@/utils/common';
 import { AxiosGetHelper } from '@/utils/axiosRequestHelper';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 import { LIMIT_OPTIONS } from '@/v2/constants/limit.constants';
 
 import {
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingDirsTable.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingDirsTable.tsx
index f0c6fc8161e..190754b9388 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingDirsTable.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingDirsTable.tsx
@@ -29,7 +29,7 @@ import SingleSelect, { Option } from 
'@/v2/components/select/singleSelect';
 import { AxiosGetHelper } from '@/utils/axiosRequestHelper';
 import { byteToSize, showDataFetchError } from '@/utils/common';
 import { getFormattedTime } from '@/v2/utils/momentUtils';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 import { LIMIT_OPTIONS } from '@/v2/constants/limit.constants';
 
 import { DeletedDirInfo } from '@/v2/types/insights.types';
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingKeysTable.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingKeysTable.tsx
index 65ada495641..81ed9020c2b 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingKeysTable.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletePendingKeysTable.tsx
@@ -29,7 +29,7 @@ import SingleSelect, { Option } from 
'@/v2/components/select/singleSelect';
 import ExpandedPendingKeysTable from 
'@/v2/components/tables/insights/expandedPendingKeysTable';
 import { AxiosGetHelper } from '@/utils/axiosRequestHelper';
 import { byteToSize, showDataFetchError } from '@/utils/common';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 import { LIMIT_OPTIONS } from '@/v2/constants/limit.constants';
 
 import {
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletedContainerKeysTable.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletedContainerKeysTable.tsx
index 9aaf62a63d6..9f665857b88 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletedContainerKeysTable.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/deletedContainerKeysTable.tsx
@@ -28,7 +28,7 @@ import Search from '@/v2/components/search/search';
 import SingleSelect, { Option } from '@/v2/components/select/singleSelect';
 import { AxiosGetHelper } from '@/utils/axiosRequestHelper';
 import { showDataFetchError } from '@/utils/common';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 import { LIMIT_OPTIONS } from '@/v2/constants/limit.constants';
 
 import {
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/openKeysTable.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/openKeysTable.tsx
index 02c73c77528..38c57f4cef2 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/openKeysTable.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/tables/insights/openKeysTable.tsx
@@ -36,7 +36,7 @@ import SingleSelect, { Option } from 
'@/v2/components/select/singleSelect';
 import { AxiosGetHelper } from '@/utils/axiosRequestHelper';
 import { byteToSize, showDataFetchError } from '@/utils/common';
 import { getFormattedTime } from '@/v2/utils/momentUtils';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 import { LIMIT_OPTIONS } from '@/v2/constants/limit.constants';
 
 import { OpenKeys, OpenKeysResponse } from '@/v2/types/insights.types';
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/constants/overview.constants.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/constants/overview.constants.tsx
new file mode 100644
index 00000000000..0429580c8e0
--- /dev/null
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/constants/overview.constants.tsx
@@ -0,0 +1,50 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import { ClusterStateResponse, KeysSummary, TaskStatus } from 
"@/v2/types/overview.types";
+
+export const DEFAULT_CLUSTER_STATE: ClusterStateResponse = {
+  missingContainers: 0,
+  totalDatanodes: 0,
+  healthyDatanodes: 0,
+  pipelines: 0,
+  storageReport: { capacity: 0, used: 0, remaining: 0, committed: 0 },
+  containers: 0,
+  volumes: 0,
+  buckets: 0,
+  keys: 0,
+  openContainers: 0,
+  deletedContainers: 0,
+  keysPendingDeletion: 0,
+  scmServiceId: 'N/A',
+  omServiceId: 'N/A'
+};
+
+export const DEFAULT_TASK_STATUS: TaskStatus[] = [];
+
+export const DEFAULT_OPEN_KEYS_SUMMARY: KeysSummary & {totalOpenKeys: number} 
= {
+  totalUnreplicatedDataSize: 0,
+  totalReplicatedDataSize: 0,
+  totalOpenKeys: 0
+};
+
+export const DEFAULT_DELETE_PENDING_KEYS_SUMMARY: KeysSummary & 
{totalDeletedKeys: number} = {
+  totalUnreplicatedDataSize: 0,
+  totalReplicatedDataSize: 0,
+  totalDeletedKeys: 0
+};
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useAPIData.hook.ts
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useAPIData.hook.ts
new file mode 100644
index 00000000000..dfcdec0cefa
--- /dev/null
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useAPIData.hook.ts
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { useState, useEffect, useRef } from 'react';
+import { AxiosGetHelper } from '@/utils/axiosRequestHelper';
+
+export interface ApiState<T> {
+  data: T;
+  loading: boolean;
+  error: string | null;
+  lastUpdated: number | null;
+}
+
+export interface UseApiDataOptions {
+  retryAttempts?: number;
+  retryDelay?: number;
+  initialFetch?: boolean;
+  onError?: (error: string) => void;
+};
+
+export function useApiData<T>(
+  url: string,
+  defaultValue: T,
+  options: UseApiDataOptions = {}
+): ApiState<T> & {
+  refetch: () => void;
+  clearError: () => void;
+} {
+  const {
+    retryAttempts = 3,
+    retryDelay = 1000,
+    initialFetch = true,
+    onError
+  } = options;
+
+  const [state, setState] = useState<ApiState<T>>({
+    data: defaultValue,
+    loading: initialFetch,
+    error: null,
+    lastUpdated: null
+  });
+
+  const controllerRef = useRef<AbortController>();
+  const retryCountRef = useRef(0);
+  const retryTimeoutRef = useRef<NodeJS.Timeout>();
+  
+  // Store stable references
+  const urlRef = useRef(url);
+  const retryAttemptsRef = useRef(retryAttempts);
+  const retryDelayRef = useRef(retryDelay);
+  const onErrorRef = useRef(onError);
+
+  // Update refs when props change
+  useEffect(() => {
+    urlRef.current = url;
+  }, [url]);
+
+  useEffect(() => {
+    retryAttemptsRef.current = retryAttempts;
+  }, [retryAttempts]);
+
+  useEffect(() => {
+    retryDelayRef.current = retryDelay;
+  }, [retryDelay]);
+
+  useEffect(() => {
+    onErrorRef.current = onError;
+  }, [onError]);
+
+
+  const fetchData = async (isRetry = false) => {
+    if (!isRetry) {
+      setState(prev => ({ ...prev, loading: true, error: null }));
+      retryCountRef.current = 0;
+    }
+
+    try {
+      const { request, controller } = AxiosGetHelper(
+        urlRef.current,
+        controllerRef.current,
+        'Request cancelled due to component unmount or new request'
+      );
+      controllerRef.current = controller;
+
+      const response = await request;
+      
+      setState({
+        data: response.data,
+        loading: false,
+        error: null,
+        lastUpdated: Date.now()
+      });
+
+      retryCountRef.current = 0;
+    } catch (error: any) {
+      if (error.name === 'CanceledError') {
+        return;
+      }
+
+      const errorMessage = error.response?.data?.message ||
+                          error.response?.statusText ||
+                          error.message ||
+                          `Request failed with status: 
${error.response?.status || 'unknown'}`;
+
+      // Clear any existing retry timeout
+      if (retryTimeoutRef.current) {
+        clearTimeout(retryTimeoutRef.current);
+      }
+
+      // Retry logic for network errors and 5xx errors
+      if (retryCountRef.current < retryAttemptsRef.current && 
+          (!error.response?.status || error.response?.status >= 500)) {
+        retryCountRef.current++;
+        retryTimeoutRef.current = setTimeout(() => {
+          fetchData(true);
+        }, retryDelayRef.current * retryCountRef.current);
+        return;
+      }
+
+      if (onErrorRef.current) {
+        onErrorRef.current(errorMessage);
+      }
+
+      setState({
+        data: defaultValue,
+        loading: false,
+        error: errorMessage,
+        lastUpdated: Date.now()
+      });
+    }
+  };
+
+  const refetch = () => {
+    fetchData();
+  };
+
+  const clearError = () => {
+    setState(prev => ({ ...prev, error: null }));
+  };
+
+  // Initial fetch only
+  useEffect(() => {
+    if (initialFetch) {
+      fetchData();
+    }
+
+    // Cleanup retry timeout on unmount
+    return () => {
+      if (retryTimeoutRef.current) {
+        clearTimeout(retryTimeoutRef.current);
+      }
+    };
+  }, []); // Empty dependency array
+
+  // Cleanup on unmount
+  useEffect(() => {
+    return () => {
+      if (controllerRef.current) {
+        controllerRef.current.abort('Component unmounted');
+      }
+      if (retryTimeoutRef.current) {
+        clearTimeout(retryTimeoutRef.current);
+      }
+    };
+  }, []);
+
+  return {
+    ...state,
+    refetch,
+    clearError
+  };
+}
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useAutoReload.hook.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useAutoReload.hook.tsx
new file mode 100644
index 00000000000..baa8190bfc9
--- /dev/null
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useAutoReload.hook.tsx
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { useEffect, useRef, useState } from 'react';
+import { AUTO_RELOAD_INTERVAL_DEFAULT } from 
'@/constants/autoReload.constants';
+
+export function useAutoReload(
+  refreshFunction: () => void,
+  interval: number = AUTO_RELOAD_INTERVAL_DEFAULT
+) {
+  const intervalRef = useRef<number>(0);
+  const [isPolling, setIsPolling] = useState<boolean>(false);
+  const refreshFunctionRef = useRef(refreshFunction);
+  const lastPollCallRef = useRef<number>(0); // This is used to store the last 
time poll was called
+
+  // Update the ref when the function changes
+  refreshFunctionRef.current = refreshFunction;
+
+  const stopPolling = () => {
+    if (intervalRef.current > 0) {
+      clearTimeout(intervalRef.current);
+      intervalRef.current = 0;
+      setIsPolling(false);
+    }
+  };
+
+  const startPolling = () => {
+    stopPolling();
+    const poll = () => {
+      /**
+       * Prevent any extra polling calls within 100ms of the last call,
+       * This is done in case at any place multiple API calls are made, for 
example
+       * the useEffect on mount in this component will call the startPolling() 
function.
+       * If this startPolling() function is called elsewhere in a different 
component then
+       * race condition can occur where this gets called in succession 
multiple times.
+       */
+      if (Date.now() - lastPollCallRef.current > 100) {
+        refreshFunctionRef.current();
+        lastPollCallRef.current = Date.now();
+      }
+      intervalRef.current = window.setTimeout(poll, interval);
+    };
+    poll();
+    setIsPolling(true);
+  };
+
+  const handleAutoReloadToggle = (checked: boolean) => {
+    sessionStorage.setItem('autoReloadEnabled', JSON.stringify(checked));
+    if (checked) {
+      startPolling();
+    } else {
+      stopPolling();
+    }
+  };
+
+  // Initialize polling on mount if auto-reload is enabled
+  useEffect(() => {
+    const autoReloadEnabled = sessionStorage.getItem('autoReloadEnabled') !== 
'false';
+    if (autoReloadEnabled) {
+      startPolling();
+    }
+
+    return () => {
+      stopPolling();
+    };
+  }, []); // Empty dependency array
+
+  return {
+    startPolling,
+    stopPolling,
+    isPolling,
+    handleAutoReloadToggle
+  };
+}
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/debounce.hook.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useDebounce.tsx
similarity index 100%
rename from 
hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/debounce.hook.tsx
rename to 
hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/hooks/useDebounce.tsx
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.tsx
index 1c039f42709..7d2c77de3c3 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.tsx
@@ -32,7 +32,7 @@ import { AutoReloadHelper } from '@/utils/autoReloadHelper';
 import { AxiosGetHelper, cancelRequests } from "@/utils/axiosRequestHelper";
 import { showDataFetchError } from '@/utils/common';
 import { LIMIT_OPTIONS } from '@/v2/constants/limit.constants';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 
 import {
   Bucket,
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/containers/containers.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/containers/containers.tsx
index 5cdbdd52625..3a784bb9932 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/containers/containers.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/containers/containers.tsx
@@ -29,7 +29,7 @@ import AutoReloadPanel from 
"@/components/autoReloadPanel/autoReloadPanel";
 import { showDataFetchError } from "@/utils/common";
 import { AutoReloadHelper } from "@/utils/autoReloadHelper";
 import { AxiosGetHelper, cancelRequests } from "@/utils/axiosRequestHelper";
-import { useDebounce } from "@/v2/hooks/debounce.hook";
+import { useDebounce } from "@/v2/hooks/useDebounce";
 
 import {
   Container,
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/datanodes/datanodes.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/datanodes/datanodes.tsx
index 33dd661d97b..7c044b2ae1e 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/datanodes/datanodes.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/datanodes/datanodes.tsx
@@ -45,7 +45,7 @@ import {
   cancelRequests
 } from '@/utils/axiosRequestHelper';
 
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 import {
   Datanode,
   DatanodeDecomissionInfo,
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/overview/overview.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/overview/overview.tsx
index 6014577f90a..70c774cd441 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/overview/overview.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/overview/overview.tsx
@@ -16,31 +16,28 @@
  * limitations under the License.
  */
 
-import React, { useEffect, useRef, useState } from 'react';
-import moment from 'moment';
-import filesize from 'filesize';
-import axios from 'axios';
+import React, { useState, useRef, useEffect } from 'react';
 import { Row, Col, Button } from 'antd';
-import {
-  CheckCircleFilled,
-  WarningFilled
-} from '@ant-design/icons';
+import { CheckCircleFilled, WarningFilled } from '@ant-design/icons';
 import { Link } from 'react-router-dom';
+import moment from 'moment';
+import filesize from 'filesize';
 
 import AutoReloadPanel from '@/components/autoReloadPanel/autoReloadPanel';
+import OverviewSimpleCard from 
'@/v2/components/overviewCard/overviewSimpleCard';
 import OverviewSummaryCard from 
'@/v2/components/overviewCard/overviewSummaryCard';
 import OverviewStorageCard from 
'@/v2/components/overviewCard/overviewStorageCard';
-import OverviewSimpleCard from 
'@/v2/components/overviewCard/overviewSimpleCard';
-
-import { AutoReloadHelper } from '@/utils/autoReloadHelper';
-import { checkResponseError, showDataFetchError } from '@/utils/common';
-import { AxiosGetHelper, cancelRequests, PromiseAllSettledGetHelper } from 
'@/utils/axiosRequestHelper';
-
-import { ClusterStateResponse, OverviewState, StorageReport } from 
'@/v2/types/overview.types';
+import { AxiosGetHelper } from '@/utils/axiosRequestHelper';
+import { showDataFetchError } from '@/utils/common';
+import { cancelRequests } from '@/utils/axiosRequestHelper';
+import { useApiData } from '@/v2/hooks/useAPIData.hook';
+import { useAutoReload } from '@/v2/hooks/useAutoReload.hook';
+import * as CONSTANTS from '@/v2/constants/overview.constants';
+import { ClusterStateResponse, KeysSummary, OverviewState, TaskStatus } from 
'@/v2/types/overview.types';
 
 import './overview.less';
 
-
+// ------------- Helper Functions -------------- //
 const size = filesize.partial({ round: 1 });
 
 const getHealthIcon = (value: string): React.ReactElement => {
@@ -82,165 +79,70 @@ const getSummaryTableValue = (
   return size(value as number)
 }
 
+// ------------- Main Component -------------- //
 const Overview: React.FC<{}> = () => {
-
-  const cancelOverviewSignal = useRef<AbortController>();
   const cancelOMDBSyncSignal = useRef<AbortController>();
-
   const [state, setState] = useState<OverviewState>({
-    loading: false,
-    datanodes: '',
-    pipelines: 0,
-    containers: 0,
-    volumes: 0,
-    buckets: 0,
-    keys: 0,
-    missingContainersCount: 0,
-    lastRefreshed: 0,
-    lastUpdatedOMDBDelta: 0,
-    lastUpdatedOMDBFull: 0,
     omStatus: '',
-    openContainers: 0,
-    deletedContainers: 0,
-    openSummarytotalUnrepSize: 0,
-    openSummarytotalRepSize: 0,
-    openSummarytotalOpenKeys: 0,
-    deletePendingSummarytotalUnrepSize: 0,
-    deletePendingSummarytotalRepSize: 0,
-    deletePendingSummarytotalDeletedKeys: 0,
-    scmServiceId: '',
-    omServiceId: ''
-  })
-  const [storageReport, setStorageReport] = useState<StorageReport>({
-    capacity: 0,
-    used: 0,
-    remaining: 0,
-    committed: 0
-  })
+    lastRefreshed: 0
+  });
 
-  // Component mounted, fetch initial data
-  useEffect(() => {
-    loadOverviewPageData();
-    autoReloadHelper.startPolling();
-    return (() => {
-      // Component will Un-mount
-      autoReloadHelper.stopPolling();
-      cancelRequests([
-        cancelOMDBSyncSignal.current!,
-        cancelOverviewSignal.current!
-      ]);
-    })
-  }, [])
-
-  const loadOverviewPageData = () => {
-    setState({
-      ...state,
-      loading: true
-    });
-
-    // Cancel any previous pending requests
-    cancelRequests([
-      cancelOMDBSyncSignal.current!,
-      cancelOverviewSignal.current!
-    ]);
+  // Individual API calls using custom hook (no auto-refresh)
+  const clusterState = useApiData<ClusterStateResponse>(
+    '/api/v1/clusterState',
+    CONSTANTS.DEFAULT_CLUSTER_STATE,
+    {
+      retryAttempts: 2,
+      initialFetch: false,
+      onError: (error) => showDataFetchError(error)
+    }
+  );
 
-    const { requests, controller } = PromiseAllSettledGetHelper([
-      '/api/v1/clusterState',
-      '/api/v1/task/status',
-      '/api/v1/keys/open/summary',
-      '/api/v1/keys/deletePending/summary'
-    ], cancelOverviewSignal.current);
-    cancelOverviewSignal.current = controller;
+  const taskStatus = useApiData<TaskStatus[]>(
+    '/api/v1/task/status',
+    CONSTANTS.DEFAULT_TASK_STATUS,
+    {
+      retryAttempts: 2,
+      initialFetch: false,
+      onError: (error) => showDataFetchError(error)
+    }
+  );
 
-    requests.then(axios.spread((
-      clusterStateResponse: Awaited<Promise<any>>,
-      taskstatusResponse: Awaited<Promise<any>>,
-      openResponse: Awaited<Promise<any>>,
-      deletePendingResponse: Awaited<Promise<any>>
-    ) => {
+  const openKeysSummary = useApiData<KeysSummary & { totalOpenKeys: number}>(
+    '/api/v1/keys/open/summary',
+    CONSTANTS.DEFAULT_OPEN_KEYS_SUMMARY,
+    {
+      retryAttempts: 2,
+      initialFetch: false,
+      onError: (error) => showDataFetchError(error)
+    }
+  );
 
-      checkResponseError([
-        clusterStateResponse,
-        taskstatusResponse,
-        openResponse,
-        deletePendingResponse
-      ]);
+  const deletePendingKeysSummary = useApiData<KeysSummary & { 
totalDeletedKeys: number}>(
+    '/api/v1/keys/deletePending/summary',
+    CONSTANTS.DEFAULT_DELETE_PENDING_KEYS_SUMMARY,
+    {
+      retryAttempts: 2,
+      initialFetch: false,
+      onError: (error) => showDataFetchError(error)
+    }
+  );
 
-      const clusterState: ClusterStateResponse = 
clusterStateResponse.value?.data ?? {
-        missingContainers: 'N/A',
-        totalDatanodes: 'N/A',
-        healthyDatanodes: 'N/A',
-        pipelines: 'N/A',
-        storageReport: {
-          capacity: 0,
-          used: 0,
-          remaining: 0,
-          committed: 0
-        },
-        containers: 'N/A',
-        volumes: 'N/A',
-        buckets: 'N/A',
-        keys: 'N/A',
-        openContainers: 'N/A',
-        deletedContainers: 'N/A',
-        keysPendingDeletion: 'N/A',
-        scmServiceId: 'N/A',
-        omServiceId: 'N/A',
-      };
-      const taskStatus = taskstatusResponse.value?.data ?? [{
-        taskName: 'N/A',
-        lastUpdatedTimestamp: 0,
-        lastUpdatedSeqNumber: 0
-      }];
-      const missingContainersCount = clusterState.missingContainers;
-      const omDBDeltaObject = taskStatus && taskStatus.find((item: any) => 
item.taskName === 'OmDeltaRequest');
-      const omDBFullObject = taskStatus && taskStatus.find((item: any) => 
item.taskName === 'OmSnapshotRequest');
+  const omDBDeltaObject = taskStatus.data?.find((item: TaskStatus) => 
item.taskName === 'OmDeltaRequest');
+  const omDBFullObject = taskStatus.data?.find((item: TaskStatus) => 
item.taskName === 'OmSnapshotRequest');
 
-      setState({
-        ...state,
-        loading: false,
-        datanodes: 
`${clusterState.healthyDatanodes}/${clusterState.totalDatanodes}`,
-        pipelines: clusterState.pipelines,
-        containers: clusterState.containers,
-        volumes: clusterState.volumes,
-        buckets: clusterState.buckets,
-        keys: clusterState.keys,
-        missingContainersCount: missingContainersCount,
-        openContainers: clusterState.openContainers,
-        deletedContainers: clusterState.deletedContainers,
-        lastRefreshed: Number(moment()),
-        lastUpdatedOMDBDelta: omDBDeltaObject?.lastUpdatedTimestamp,
-        lastUpdatedOMDBFull: omDBFullObject?.lastUpdatedTimestamp,
-        openSummarytotalUnrepSize: 
openResponse?.value?.data?.totalUnreplicatedDataSize,
-        openSummarytotalRepSize: 
openResponse?.value?.data?.totalReplicatedDataSize,
-        openSummarytotalOpenKeys: openResponse?.value?.data?.totalOpenKeys,
-        deletePendingSummarytotalUnrepSize: 
deletePendingResponse?.value?.data?.totalUnreplicatedDataSize,
-        deletePendingSummarytotalRepSize: 
deletePendingResponse?.value?.data?.totalReplicatedDataSize,
-        deletePendingSummarytotalDeletedKeys: 
deletePendingResponse?.value?.data?.totalDeletedKeys,
-        scmServiceId: clusterState?.scmServiceId ?? 'N/A',
-        omServiceId: clusterState?.omServiceId ?? 'N/A'
-      });
-      setStorageReport({
-        ...storageReport,
-        ...clusterState.storageReport
-      });
-    })).catch((error: Error) => {
-      setState({
-        ...state,
-        loading: false
-      });
-      showDataFetchError(error.toString());
-    });
-  }
-
-  let autoReloadHelper: AutoReloadHelper = new 
AutoReloadHelper(loadOverviewPageData);
+  const loadOverviewPageData = () => {
+    clusterState.refetch();
+    taskStatus.refetch();
+    openKeysSummary.refetch();
+    deletePendingKeysSummary.refetch();
+    setState(prev => ({ ...prev, lastRefreshed: Number(moment()) }));
+  };
+  
+  const autoReload = useAutoReload(loadOverviewPageData);
 
+  // OM DB Sync function
   const syncOmData = () => {
-    setState({
-      ...state,
-      loading: true
-    });
-
     const { request, controller } = AxiosGetHelper(
       '/api/v1/triggerdbsync/om',
       cancelOMDBSyncSignal.current,
@@ -250,56 +152,36 @@ const Overview: React.FC<{}> = () => {
 
     request.then(omStatusResponse => {
       const omStatus = omStatusResponse.data;
-      setState({
-        ...state,
-        loading: false,
-        omStatus: omStatus
-      });
+      setState(prev => ({ ...prev, omStatus }));
     }).catch((error: Error) => {
-      setState({
-        ...state,
-        loading: false
-      });
       showDataFetchError(error.toString());
     });
   };
 
-  const {
-    loading, datanodes, pipelines,
-    containers, volumes, buckets,
-    openSummarytotalUnrepSize,
-    openSummarytotalRepSize,
-    openSummarytotalOpenKeys,
-    deletePendingSummarytotalUnrepSize,
-    deletePendingSummarytotalRepSize,
-    deletePendingSummarytotalDeletedKeys,
-    keys, missingContainersCount,
-    lastRefreshed, lastUpdatedOMDBDelta,
-    lastUpdatedOMDBFull,
-    omStatus, openContainers,
-    deletedContainers, scmServiceId, omServiceId
-  } = state;
+  useEffect(() => {
+    return () => {
+      cancelRequests([cancelOMDBSyncSignal.current!]);
+    };
+  }, []);
 
   const healthCardIndicators = (
     <>
       <Col span={14}>
         Datanodes
-        {getHealthIcon(datanodes)}
+        
{getHealthIcon(`${clusterState.data?.healthyDatanodes}/${clusterState.data?.totalDatanodes}`)}
       </Col>
       <Col span={10}>
         Containers
-        {getHealthIcon(`${(containers - 
missingContainersCount)}/${containers}`)}
+        {getHealthIcon(`${(clusterState.data?.containers || 0) - 
(clusterState.data?.missingContainers || 0)}/${clusterState.data?.containers}`)}
       </Col>
     </>
-  )
+  );
 
   const datanodesLink = (
-    <Button
-      type='link'
-      size='small'>
+    <Button type='link' size='small'>
       <Link to='/Datanodes'> View More </Link>
     </Button>
-  )
+  );
 
   const containersLink = (
     <Button
@@ -309,13 +191,39 @@ const Overview: React.FC<{}> = () => {
     </Button>
   )
 
+  const loading = clusterState.loading || taskStatus.loading || 
openKeysSummary.loading || deletePendingKeysSummary.loading;
+  const {
+    healthyDatanodes,
+    totalDatanodes,
+    containers,
+    missingContainers,
+    storageReport,
+    volumes,
+    buckets,
+    keys,
+    pipelines,
+    deletedContainers,
+    omServiceId,
+    scmServiceId
+  } = clusterState.data;
+  const {
+    totalReplicatedDataSize: openSummarytotalRepSize,
+    totalUnreplicatedDataSize: openSummarytotalUnrepSize,
+    totalOpenKeys: openSummarytotalOpenKeys,
+  } = openKeysSummary.data ?? {};
+  const {
+    totalReplicatedDataSize: deletePendingSummarytotalRepSize,  
+    totalUnreplicatedDataSize: deletePendingSummarytotalUnrepSize,
+    totalDeletedKeys: deletePendingSummarytotalDeletedKeys
+  } = deletePendingKeysSummary.data ?? {};
+
   return (
     <>
       <div className='page-header-v2'>
         Overview
-        <AutoReloadPanel isLoading={loading} lastRefreshed={lastRefreshed}
-          lastUpdatedOMDBDelta={lastUpdatedOMDBDelta} 
lastUpdatedOMDBFull={lastUpdatedOMDBFull}
-          togglePolling={autoReloadHelper.handleAutoReloadToggle} 
onReload={loadOverviewPageData} omSyncLoad={syncOmData} omStatus={omStatus} />
+        <AutoReloadPanel isLoading={loading} 
lastRefreshed={state.lastRefreshed}
+          lastUpdatedOMDBDelta={omDBDeltaObject?.lastUpdatedTimestamp} 
lastUpdatedOMDBFull={omDBFullObject?.lastUpdatedTimestamp}
+          togglePolling={autoReload.handleAutoReloadToggle} 
onReload={loadOverviewPageData} omSyncLoad={syncOmData} 
omStatus={state.omStatus} />
       </div>
       <div className='data-container'>
         <Row
@@ -333,6 +241,7 @@ const Overview: React.FC<{}> = () => {
               title='Health'
               data={healthCardIndicators}
               showHeader={true}
+              loading={clusterState.loading}
               columns={[
                 {
                   title: '',
@@ -356,20 +265,21 @@ const Overview: React.FC<{}> = () => {
                 {
                   key: 'datanodes',
                   name: 'Datanodes',
-                  value: datanodes,
+                  value: `${healthyDatanodes}/${totalDatanodes}`,
                   action: datanodesLink
                 },
                 {
                   key: 'containers',
                   name: 'Containers',
-                  value: `${(containers - 
missingContainersCount)}/${containers}`,
+                  value: `${containers - missingContainers}/${containers}`,
                   action: containersLink
                 }
               ]}
+              error={clusterState.error}
             />
           </Col>
           <Col xs={24} sm={24} md={24} lg={14} xl={14}>
-            <OverviewStorageCard storageReport={storageReport} 
loading={loading} />
+            <OverviewStorageCard storageReport={storageReport} 
loading={loading} error={clusterState.error}/>
           </Col>
         </Row>
         <Row gutter={[
@@ -384,39 +294,44 @@ const Overview: React.FC<{}> = () => {
             <OverviewSimpleCard
               title='Volumes'
               icon='inbox'
-              loading={loading}
+              loading={clusterState.loading}
               data={volumes}
-              linkToUrl='/Volumes' />
+              linkToUrl='/Volumes'
+              error={clusterState.error} />
           </Col>
           <Col flex="1 0 20%">
             <OverviewSimpleCard
               title='Buckets'
               icon='folder-open'
-              loading={loading}
+              loading={clusterState.loading}
               data={buckets}
-              linkToUrl='/Buckets' />
+              linkToUrl='/Buckets'
+              error={clusterState.error} />
           </Col>
           <Col flex="1 0 20%">
             <OverviewSimpleCard
               title='Keys'
               icon='file-text'
-              loading={loading}
-              data={keys} />
+              loading={clusterState.loading}
+              data={keys}
+              error={clusterState.error} />
           </Col>
           <Col flex="1 0 20%">
             <OverviewSimpleCard
               title='Pipelines'
               icon='deployment-unit'
-              loading={loading}
+              loading={clusterState.loading}
               data={pipelines}
-              linkToUrl='/Pipelines' />
+              linkToUrl='/Pipelines'
+              error={clusterState.error} />
           </Col>
           <Col flex="1 0 20%">
             <OverviewSimpleCard
               title='Deleted Containers'
               icon='delete'
-              loading={loading}
-              data={deletedContainers} />
+              loading={clusterState.loading}
+              data={deletedContainers}
+              error={clusterState.error} />
           </Col>
         </Row>
         <Row gutter={[
@@ -430,7 +345,7 @@ const Overview: React.FC<{}> = () => {
           <Col xs={24} sm={24} md={24} lg={12} xl={12}>
             <OverviewSummaryCard
               title='Open Keys Summary'
-              loading={loading}
+              loading={openKeysSummary.loading}
               columns={[
                 {
                   title: 'Name',
@@ -465,12 +380,13 @@ const Overview: React.FC<{}> = () => {
                 }
               ]}
               linkToUrl='/Om'
-              state={{activeTab: '2'}} />
+              state={{activeTab: '2'}}
+              error={openKeysSummary.error} />
           </Col>
           <Col xs={24} sm={24} md={24} lg={12} xl={12}>
             <OverviewSummaryCard
               title='Delete Pending Keys Summary'
-              loading={loading}
+              loading={deletePendingKeysSummary.loading}
               columns={[
                 {
                   title: 'Name',
@@ -505,7 +421,8 @@ const Overview: React.FC<{}> = () => {
                 }
               ]}
               linkToUrl='/Om'
-              state={{activeTab: '3'}} />
+              state={{activeTab: '3'}}
+              error={deletePendingKeysSummary.error} />
           </Col>
         </Row>
         <span style={{ paddingLeft: '8px' }}>
@@ -522,4 +439,4 @@ const Overview: React.FC<{}> = () => {
   );
 }
 
-export default Overview;
\ No newline at end of file
+export default Overview;
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/pipelines/pipelines.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/pipelines/pipelines.tsx
index f6ff87c7e13..19a3c9447a6 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/pipelines/pipelines.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/pipelines/pipelines.tsx
@@ -31,7 +31,7 @@ import PipelinesTable, { COLUMNS } from 
'@/v2/components/tables/pipelinesTable';
 import { showDataFetchError } from '@/utils/common';
 import { AutoReloadHelper } from '@/utils/autoReloadHelper';
 import { AxiosGetHelper, cancelRequests } from '@/utils/axiosRequestHelper';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 
 import {
   Pipeline,
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/volumes/volumes.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/volumes/volumes.tsx
index b4614d387f3..a10b71282ce 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/volumes/volumes.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/volumes/volumes.tsx
@@ -31,7 +31,7 @@ import { showDataFetchError } from '@/utils/common';
 import { AutoReloadHelper } from '@/utils/autoReloadHelper';
 import { AxiosGetHelper, cancelRequests } from "@/utils/axiosRequestHelper";
 import { LIMIT_OPTIONS } from '@/v2/constants/limit.constants';
-import { useDebounce } from '@/v2/hooks/debounce.hook';
+import { useDebounce } from '@/v2/hooks/useDebounce';
 
 import {
   Volume,
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/overview.types.ts
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/overview.types.ts
index f8390fd4346..ef3043f8955 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/overview.types.ts
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/overview.types.ts
@@ -33,29 +33,15 @@ export type ClusterStateResponse = {
   omServiceId: string;
 }
 
-export type OverviewState = {
-  loading: boolean;
-  datanodes: string;
-  pipelines: number;
-  containers: number;
-  volumes: number;
-  buckets: number;
-  keys: number;
-  missingContainersCount: number;
-  lastRefreshed: number;
-  lastUpdatedOMDBDelta: number;
-  lastUpdatedOMDBFull: number;
-  omStatus: string;
-  openContainers: number;
-  deletedContainers: number;
-  openSummarytotalUnrepSize: number;
-  openSummarytotalRepSize: number;
-  openSummarytotalOpenKeys: number;
-  deletePendingSummarytotalUnrepSize: number;
-  deletePendingSummarytotalRepSize: number;
-  deletePendingSummarytotalDeletedKeys: number;
-  scmServiceId: string;
-  omServiceId: string;
+export type TaskStatus = {
+  taskName: 'OmDeltaRequest' | 'OmSnapshotRequest' | string;
+  lastUpdatedTimestamp: number;
+  lastUpdatedSeqNumber: number;
+}
+
+export type KeysSummary = {
+  totalUnreplicatedDataSize: number;
+  totalReplicatedDataSize: number;
 }
 
 export type StorageReport = {
@@ -64,3 +50,8 @@ export type StorageReport = {
   remaining: number;
   committed: number;
 }
+
+export type OverviewState = {
+  omStatus: string;
+  lastRefreshed: number;
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to