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 0c924bcc6a HDDS-11150. Recon Overview page crashes due to failed API 
Calls (#6944)
0c924bcc6a is described below

commit 0c924bcc6a74aa8923582ad6c6a535af4894d662
Author: Abhishek Pal <[email protected]>
AuthorDate: Fri Jul 19 11:12:36 2024 +0530

    HDDS-11150. Recon Overview page crashes due to failed API Calls (#6944)
---
 .../src/components/overviewCard/overviewCard.tsx   |  10 +-
 .../src/utils/axiosRequestHelper.tsx               |   6 +-
 .../src/views/diskUsage/diskUsage.tsx              |   6 -
 .../src/views/insights/insights.tsx                | 149 +++++++++++--
 .../src/views/overview/overview.tsx                | 247 +++++++++++++++------
 5 files changed, 320 insertions(+), 98 deletions(-)

diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
index 93c0cae1f1..78ba56e548 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/overviewCard/overviewCard.tsx
@@ -139,8 +139,14 @@ class OverviewCard extends 
React.Component<IOverviewCardProps> {
 
   render() {
     let { icon, data, title, loading, hoverable, storageReport, linkToUrl, 
error } = this.props;
+
     let meta = <Meta title={data} description={title} />;
-    const errorClass = error ? 'card-error' : '';
+    let errorClass = error ? 'card-error' : '';
+
+    if (typeof data === 'string' && data === 'N/A'){
+      errorClass = 'card-error';
+    }
+
     if (storageReport) {
       meta = (
         <div className='ant-card-percentage'>
@@ -156,7 +162,7 @@ class OverviewCard extends 
React.Component<IOverviewCardProps> {
 
     return (
       <OverviewCardWrapper linkToUrl={linkToUrl}>
-        <Card className={`overview-card ${ errorClass }`} loading={loading} 
hoverable={hoverable}>
+        <Card className={`overview-card ${errorClass}`} loading={loading} 
hoverable={hoverable}>
           <Row type='flex' justify='space-between'>
             <Col span={18}>
               <Row>
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/utils/axiosRequestHelper.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/utils/axiosRequestHelper.tsx
index 45fa3b58b6..41774088c5 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/utils/axiosRequestHelper.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/utils/axiosRequestHelper.tsx
@@ -48,11 +48,11 @@ export const AxiosPutHelper = (
   }
 }
 
-export const AxiosAllGetHelper = (
+export const PromiseAllSettledGetHelper = (
   urls: string[],
   controller: AbortController,
   message: string = ''
-): { requests: Promise<AxiosResponse<any, any>[]>; controller: AbortController 
} => {
+): { requests: Promise<PromiseSettledResult<AxiosResponse<any, any>>[]>; 
controller: AbortController } => {
 
   controller && controller.abort(message);
   controller = new AbortController(); // generate new AbortController for the 
upcoming request
@@ -64,7 +64,7 @@ export const AxiosAllGetHelper = (
   });
 
   return {
-    requests: axios.all(axiosGetRequests),
+    requests: Promise.allSettled(axiosGetRequests),
     controller: controller
   }
 }
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/diskUsage/diskUsage.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/diskUsage/diskUsage.tsx
index 60b779bdf0..091d8a146d 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/diskUsage/diskUsage.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/diskUsage/diskUsage.tsx
@@ -556,12 +556,6 @@ export class DiskUsage extends 
React.Component<Record<string, object>, IDUState>
       </Menu>
     )
 
-    console.log(plotData);
-    console.log(plotData.map((value) => {
-      return {
-        name: value.name
-      }
-    }))
     const eChartsOptions = {
       title: {
         text: `Disk Usage for ${returnPath} (Total Size: 
${byteToSize(duResponse.size, 1)})`,
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/insights/insights.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/insights/insights.tsx
index 2412febdee..f273f758ea 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/insights/insights.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/insights/insights.tsx
@@ -17,17 +17,17 @@
  */
 
 import React from 'react';
-import axios from 'axios';
+import axios, { CanceledError, AxiosError } from 'axios';
 import filesize from 'filesize';
-import { Row, Col, Tabs } from 'antd';
+import { Row, Col, Tabs, message } from 'antd';
 import { LoadingOutlined } from '@ant-design/icons';
 import { ActionMeta, ValueType } from 'react-select';
-import { format, type EChartsOption } from 'echarts';
+import { graphic, type EChartsOption } from 'echarts';
 
 import { EChart } from '@/components/eChart/eChart';
 import { MultiSelect, IOption } from '@/components/multiSelect/multiSelect';
 import { showDataFetchError } from '@/utils/common';
-import { AxiosAllGetHelper } from '@/utils/axiosRequestHelper';
+import { PromiseAllSettledGetHelper, PromiseAllSettledError } from 
'@/utils/axiosRequestHelper';
 
 import './insights.less';
 
@@ -58,6 +58,8 @@ interface IInsightsState {
   bucketOptions: IOption[];
   volumeOptions: IOption[];
   isBucketSelectionDisabled: boolean;
+  fileCountError: string | undefined;
+  containerSizeError: string | undefined;
 }
 
 const allVolumesOption: IOption = {
@@ -86,7 +88,9 @@ export class Insights extends React.Component<Record<string, 
object>, IInsightsS
       selectedVolumes: [],
       bucketOptions: [],
       volumeOptions: [],
-      isBucketSelectionDisabled: false
+      isBucketSelectionDisabled: false,
+      fileCountError: undefined,
+      containerSizeError: undefined
     };
   }
 
@@ -195,9 +199,81 @@ export class Insights extends 
React.Component<Record<string, object>, IInsightsS
         return (size(value));
       });
 
-      console.log(xyFileCountMap);
-      console.log(xContainerCountValues);
-      console.log(xyContainerCountMap);
+      let renderFileCountError = (this.state.fileCountError) ? {
+        type: 'group',
+        left: 'center',
+        top: 'middle',
+        z: 100,
+        children: [
+          {
+            type: 'rect',
+            left: 'center',
+            top: 'middle',
+            z: 100,
+            shape: {
+              width: 500,
+              height: 40
+            },
+            style: {
+              fill: '#FC909B'
+            }
+          },
+          {
+            type: 'text',
+            left: 'center',
+            top: 'middle',
+            z: 100,
+            style: {
+              text: `No data available. ${this.state.fileCountError}`,
+              font: '20px sans-serif'
+            }
+          }
+        ]
+      } : undefined
+      let renderContainerSizeError = (this.state.containerSizeError) ? {
+        type: 'group',
+        left: 'center',
+        top: 'middle',
+        z: 100,
+        children: [
+          {
+            type: 'rect',
+            left: 'center',
+            top: 'middle',
+            z: 100,
+            shape: {
+              width: 500,
+              height: 500
+            },
+            style: {
+              fill: 'rgba(256, 256, 256, 0.5)'
+            }
+          },
+          {
+            type: 'rect',
+            left: 'center',
+            top: 'middle',
+            z: 100,
+            shape: {
+              width: 500,
+              height: 40
+            },
+            style: {
+              fill: '#FC909B'
+            }
+          },
+          {
+            type: 'text',
+            left: 'center',
+            top: 'middle',
+            z: 100,
+            style: {
+              text: `No data available. ${this.state.containerSizeError}`,
+              font: '20px sans-serif'
+            }
+          }
+        ]
+      } : undefined
 
       this.setState({
         fileCountData: {
@@ -224,7 +300,8 @@ export class Insights extends 
React.Component<Record<string, object>, IInsightsS
             },
             data: Array.from(xyFileCountMap.values()),
             type: 'bar'
-          }
+          },
+          graphic: renderFileCountError
         },
         containerCountData: {
           title: {
@@ -250,7 +327,8 @@ export class Insights extends 
React.Component<Record<string, object>, IInsightsS
                 name: xContainerCountValues[idx]
               }
             }),
-          }
+          },
+          graphic: renderContainerSizeError
         }
       });
     }
@@ -261,15 +339,50 @@ export class Insights extends 
React.Component<Record<string, object>, IInsightsS
     this.setState({
       isLoading: true
     });
-    const { requests, controller } = AxiosAllGetHelper([
+    const { requests, controller } = PromiseAllSettledGetHelper([
       '/api/v1/utilization/fileCount',
       '/api/v1/utilization/containerCount'
     ], cancelInsightSignal);
 
     cancelInsightSignal = controller;
-    requests.then(axios.spread((fileCountresponse, containerCountresponse) => {
-      const fileCountsResponse: IFileCountResponse[] = fileCountresponse.data;
-      const containerCountResponse: IContainerCountResponse[] = 
containerCountresponse.data;
+    requests.then(axios.spread((
+      fileCountresponse: Awaited<Promise<any>>,
+      containerCountresponse: Awaited<Promise<any>>
+    ) => {
+      let fileAPIError = undefined;
+      let containerAPIError = undefined;
+      let responseError = [
+        fileCountresponse,
+        containerCountresponse
+      ].filter((resp) => resp.status === 'rejected');
+
+      if (responseError.length !== 0) {
+        responseError.forEach((err) => {
+          if (err.reason.toString().includes("CanceledError")) {
+            throw new CanceledError('canceled', "ERR_CANCELED");
+          }
+          else {
+            if (err.reason.config.url.includes("fileCount")) {
+              fileAPIError = err.reason.toString();
+            }
+            else {
+              containerAPIError = err.reason.toString();
+            }
+          }
+        })
+      }
+
+      const fileCountsResponse: IFileCountResponse[] = 
fileCountresponse.value?.data ?? [{
+        volume: '0',
+        bucket: '0',
+        fileSize: '0',
+        count: 0
+      }];
+      const containerCountResponse: IContainerCountResponse[] = 
containerCountresponse.value?.data ?? [{
+        containerSize: 0,
+        count: 0
+      }];
+
       // Construct volume -> bucket[] map for populating filters
       // Ex: vol1 -> [bucket1, bucket2], vol2 -> [bucket1]
       const volumeBucketMap: Map<string, Set<string>> = 
fileCountsResponse.reduce(
@@ -280,7 +393,7 @@ export class Insights extends 
React.Component<Record<string, object>, IInsightsS
             const buckets = Array.from(map.get(volume)!);
             map.set(volume, new Set([...buckets, bucket]));
           } else {
-            map.set(volume, new Set().add(bucket));
+            map.set(volume, new Set<string>().add(bucket));
           }
 
           return map;
@@ -297,7 +410,9 @@ export class Insights extends 
React.Component<Record<string, object>, IInsightsS
         volumeBucketMap,
         fileCountsResponse,
         containerCountResponse,
-        volumeOptions
+        volumeOptions,
+        fileCountError: fileAPIError,
+        containerSizeError: containerAPIError
       }, () => {
         this.updatePlotData();
         // Select all volumes by default
@@ -305,7 +420,7 @@ export class Insights extends 
React.Component<Record<string, object>, IInsightsS
       });
     })).catch(error => {
       this.setState({
-        isLoading: false
+        isLoading: false,
       });
       showDataFetchError(error.toString());
     });
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
index 5b27b3f0d0..bb2e5e02f2 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/overview/overview.tsx
@@ -17,7 +17,7 @@
  */
 
 import React from 'react';
-import axios from 'axios';
+import axios, { CanceledError } from 'axios';
 import moment from 'moment';
 import filesize from 'filesize';
 import { Row, Col, Tooltip } from 'antd';
@@ -28,25 +28,25 @@ import OverviewCard from 
'@/components/overviewCard/overviewCard';
 import AutoReloadPanel from '@/components/autoReloadPanel/autoReloadPanel';
 import { AutoReloadHelper } from '@/utils/autoReloadHelper';
 import { showDataFetchError, byteToSize } from '@/utils/common';
-import { AxiosAllGetHelper, AxiosGetHelper, cancelRequests } from 
'@/utils/axiosRequestHelper';
+import { AxiosGetHelper, cancelRequests, PromiseAllSettledGetHelper } from 
'@/utils/axiosRequestHelper';
 
 import './overview.less';
 
 const size = filesize.partial({ round: 1 });
 
 interface IClusterStateResponse {
-  missingContainers: number;
-  totalDatanodes: number;
-  healthyDatanodes: number;
-  pipelines: number;
+  missingContainers: number | string;
+  totalDatanodes: number | string;
+  healthyDatanodes: number | string;
+  pipelines: number | string;
   storageReport: IStorageReport;
-  containers: number;
-  volumes: number;
-  buckets: number;
-  keys: number;
-  openContainers: number;
-  deletedContainers: number;
-  keysPendingDeletion: number;
+  containers: number | string;
+  volumes: number | string;
+  buckets: number | string;
+  keys: number | string;
+  openContainers: number | string;
+  deletedContainers: number | string;
+  keysPendingDeletion: number | string;
   scmServiceId: string;
   omServiceId: string;
 }
@@ -54,25 +54,25 @@ interface IClusterStateResponse {
 interface IOverviewState {
   loading: boolean;
   datanodes: string;
-  pipelines: number;
+  pipelines: number | string;
   storageReport: IStorageReport;
-  containers: number;
-  volumes: number;
-  buckets: number;
-  keys: number;
-  missingContainersCount: number;
-  lastRefreshed: number;
-  lastUpdatedOMDBDelta: number;
-  lastUpdatedOMDBFull: number;
+  containers: number | string;
+  volumes: number | string;
+  buckets: number | string;
+  keys: number | string;
+  missingContainersCount: number | string;
+  lastRefreshed: number | string;
+  lastUpdatedOMDBDelta: number | string;
+  lastUpdatedOMDBFull: number | string;
   omStatus: string;
-  openContainers: number;
-  deletedContainers: number;
-  openSummarytotalUnrepSize: number;
-  openSummarytotalRepSize: number;
-  openSummarytotalOpenKeys: number;
-  deletePendingSummarytotalUnrepSize: number;
-  deletePendingSummarytotalRepSize: number;
-  deletePendingSummarytotalDeletedKeys: number;
+  openContainers: number | string;
+  deletedContainers: number | string;
+  openSummarytotalUnrepSize: number | string;
+  openSummarytotalRepSize: number | string;
+  openSummarytotalOpenKeys: number | string;
+  deletePendingSummarytotalUnrepSize: number | string;
+  deletePendingSummarytotalRepSize: number | string;
+  deletePendingSummarytotalDeletedKeys: number | string;
   scmServiceId: string;
   omServiceId: string;
 }
@@ -127,7 +127,7 @@ export class Overview extends 
React.Component<Record<string, object>, IOverviewS
       cancelOverviewSignal
     ]);
 
-    const { requests, controller } = AxiosAllGetHelper([
+    const { requests, controller } = PromiseAllSettledGetHelper([
       '/api/v1/clusterState',
       '/api/v1/task/status',
       '/api/v1/keys/open/summary',
@@ -135,17 +135,65 @@ export class Overview extends 
React.Component<Record<string, object>, IOverviewS
     ], cancelOverviewSignal);
     cancelOverviewSignal = controller;
 
-    requests.then(axios.spread((clusterStateResponse, taskstatusResponse, 
openResponse, deletePendingResponse) => {
+    requests.then(axios.spread((
+      clusterStateResponse: Awaited<Promise<any>>,
+      taskstatusResponse: Awaited<Promise<any>>,
+      openResponse: Awaited<Promise<any>>,
+      deletePendingResponse: Awaited<Promise<any>>
+    ) => {
+      let responseError = [
+        clusterStateResponse,
+        taskstatusResponse,
+        openResponse,
+        deletePendingResponse
+      ].filter((resp) => resp.status === 'rejected');
 
-      const clusterState: IClusterStateResponse = clusterStateResponse.data;
-      const taskStatus = taskstatusResponse.data;
+      if (responseError.length !== 0) {
+        responseError.forEach((err) => {
+          if (err.reason.toString().includes("CanceledError")){
+            throw new CanceledError('canceled', "ERR_CANCELED");
+          }
+          else {
+            const reqMethod = err.reason.config.method;
+            const reqURL = err.reason.config.url
+            showDataFetchError(`Failed to ${reqMethod} URL 
${reqURL}\n${err.reason.toString()}`);
+          }
+        })
+      }
+
+      const clusterState: IClusterStateResponse = 
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');
 
       this.setState({
         loading: false,
-        datanodes: 
`${clusterState.healthyDatanodes}/${clusterState.totalDatanodes}`,
+        datanodes: clusterState.healthyDatanodes !== 'N/A'
+          ? `${clusterState.healthyDatanodes}/${clusterState.totalDatanodes}`
+          : `N/A`,
         storageReport: clusterState.storageReport,
         pipelines: clusterState.pipelines,
         containers: clusterState.containers,
@@ -158,12 +206,12 @@ export class Overview extends 
React.Component<Record<string, object>, IOverviewS
         lastRefreshed: Number(moment()),
         lastUpdatedOMDBDelta: omDBDeltaObject && 
omDBDeltaObject.lastUpdatedTimestamp,
         lastUpdatedOMDBFull: omDBFullObject && 
omDBFullObject.lastUpdatedTimestamp,
-        openSummarytotalUnrepSize: openResponse.data && 
openResponse.data.totalUnreplicatedDataSize,
-        openSummarytotalRepSize: openResponse.data && 
openResponse.data.totalReplicatedDataSize,
-        openSummarytotalOpenKeys: openResponse.data && 
openResponse.data.totalOpenKeys,
-        deletePendingSummarytotalUnrepSize: deletePendingResponse.data && 
deletePendingResponse.data.totalUnreplicatedDataSize,
-        deletePendingSummarytotalRepSize: deletePendingResponse.data && 
deletePendingResponse.data.totalReplicatedDataSize,
-        deletePendingSummarytotalDeletedKeys: deletePendingResponse.data && 
deletePendingResponse.data.totalDeletedKeys,
+        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,
         omServiceId: clusterState.omServiceId
       });
@@ -221,43 +269,89 @@ export class Overview extends 
React.Component<Record<string, object>, IOverviewS
       keys, missingContainersCount, lastRefreshed, lastUpdatedOMDBDelta, 
lastUpdatedOMDBFull,
       omStatus, openContainers, deletedContainers, scmServiceId, omServiceId } 
= this.state;
 
-    const datanodesElement = (
-      <span>
-        <CheckCircleFilled className='icon-success icon-small' /> {datanodes} 
<span className='ant-card-meta-description meta'>HEALTHY</span>
-      </span>
-    );
+    let openKeysError: boolean = false;
+    let pendingDeleteKeysError: boolean = false;
+    if ([
+      openSummarytotalRepSize,
+      openSummarytotalUnrepSize,
+      openSummarytotalOpenKeys].some(
+        (data) => data === undefined
+      )) {
+      openKeysError = true;
+    }
+
+    if ([
+      deletePendingSummarytotalRepSize,
+      deletePendingSummarytotalUnrepSize,
+      deletePendingSummarytotalDeletedKeys].some(
+        (data) => data === undefined
+      )) {
+        pendingDeleteKeysError = true;
+      }
+    const datanodesElement = datanodes !== 'N/A'
+      ? (
+        <span>
+          <CheckCircleFilled className='icon-success icon-small' /> 
{datanodes} <span className='ant-card-meta-description meta'>HEALTHY</span>
+        </span>
+      )
+      : (
+        <span>
+          <Tooltip
+            placement='bottom'
+            title={'Failed to fetch Datanodes count'}>
+            <ExclamationCircleFilled className='icon-failure icon-small' />
+            <span className='padded-text'>{datanodes}</span>
+            <span className='ant-card-meta-description meta 
padded-text'>UNHEALTHY</span>
+          </Tooltip>
+        </span>
+      )
     const openSummaryData = (
       <div>
-        {openSummarytotalRepSize !== undefined ? 
byteToSize(openSummarytotalRepSize, 1) : '0'}   <span 
className='ant-card-meta-description meta'>Total Replicated Data Size</span><br 
/>
-        {openSummarytotalUnrepSize !== undefined ? 
byteToSize(openSummarytotalUnrepSize, 1) : '0'}  <span 
className='ant-card-meta-description meta'>Total UnReplicated Data 
Size</span><br />
-        {openSummarytotalOpenKeys !== undefined ? openSummarytotalOpenKeys : 
'0'}  <span className='ant-card-meta-description meta'>Total Open Keys</span>
+        {openSummarytotalRepSize !== undefined ? 
byteToSize(openSummarytotalRepSize, 1) : 'N/A'}   <span 
className='ant-card-meta-description meta'>Total Replicated Data Size</span><br 
/>
+        {openSummarytotalUnrepSize !== undefined ? 
byteToSize(openSummarytotalUnrepSize, 1) : 'N/A'}  <span 
className='ant-card-meta-description meta'>Total UnReplicated Data 
Size</span><br />
+        {openSummarytotalOpenKeys !== undefined ? openSummarytotalOpenKeys : 
'N/A'}  <span className='ant-card-meta-description meta'>Total Open Keys</span>
       </div>
     );
     const deletePendingSummaryData = (
       <div>
-        {deletePendingSummarytotalRepSize !== undefined ? 
byteToSize(deletePendingSummarytotalRepSize, 1) : '0'}  <span 
className='ant-card-meta-description meta'>Total Replicated Data Size</span><br 
/>
-        {deletePendingSummarytotalUnrepSize !== undefined ? 
byteToSize(deletePendingSummarytotalUnrepSize, 1) : '0'}  <span 
className='ant-card-meta-description meta'>Total UnReplicated Data 
Size</span><br />
-        {deletePendingSummarytotalDeletedKeys !== undefined ? 
deletePendingSummarytotalDeletedKeys : '0'}  <span 
className='ant-card-meta-description meta'>Total Pending Delete Keys</span>
+        {deletePendingSummarytotalRepSize !== undefined ? 
byteToSize(deletePendingSummarytotalRepSize, 1) : 'N/A'}  <span 
className='ant-card-meta-description meta'>Total Replicated Data Size</span><br 
/>
+        {deletePendingSummarytotalUnrepSize !== undefined ? 
byteToSize(deletePendingSummarytotalUnrepSize, 1) : 'N/A'}  <span 
className='ant-card-meta-description meta'>Total UnReplicated Data 
Size</span><br />
+        {deletePendingSummarytotalDeletedKeys !== undefined ? 
deletePendingSummarytotalDeletedKeys : 'N/A'}  <span 
className='ant-card-meta-description meta'>Total Pending Delete Keys</span>
       </div>
     );
     const containersTooltip = missingContainersCount === 1 ? 'container is 
missing' : 'containers are missing';
-    const containersLink = missingContainersCount > 0 ? '/MissingContainers' : 
'/Containers';
+    const containersLink = missingContainersCount as number > 0 ? 
'/MissingContainers' : '/Containers';
     const volumesLink = '/Volumes';
     const bucketsLink = '/Buckets';
-    const containersElement = missingContainersCount > 0 ? (
-      <span>
-        <Tooltip placement='bottom' title={missingContainersCount > 1000 ? 
`1000+ Containers are missing. For more information, go to the Containers 
page.` : `${missingContainersCount} ${containersTooltip}`}>
-          <ExclamationCircleFilled className='icon-failure icon-small' />
-        </Tooltip>
-        <span className='padded-text'>{containers - 
missingContainersCount}/{containers}</span>
-      </span>
-    ) :
-      <div>
-        <span>{containers.toString()}   </span>
-        <Tooltip placement='bottom' title='Number of open containers'>
-          <span>({openContainers})</span>
-        </Tooltip>
-      </div>
+    const containersElement = missingContainersCount !== 'N/A'
+      ? missingContainersCount as number > 0
+        ? (<span>
+          <Tooltip
+            placement='bottom'
+            title={
+              missingContainersCount as number > 1000
+                ? `1000+ Containers are missing. For more information, go to 
the Containers page.`
+                : `${missingContainersCount} ${containersTooltip}`}>
+            <ExclamationCircleFilled className='icon-failure icon-small' />
+          </Tooltip>
+          <span className='padded-text'>{(containers as number) - 
(missingContainersCount as number)}/{containers}</span>
+        </span>
+        )
+        :
+        (<div>
+          <span>{containers.toString()}   </span>
+          <Tooltip placement='bottom' title='Number of open containers'>
+            <span>({openContainers})</span>
+          </Tooltip>
+        </div>)
+      : (
+        <span>
+          <Tooltip placement='bottom' title={`Failed to fetch Container 
Count`}>
+            <ExclamationCircleFilled className='icon-failure icon-small' />
+            <span className='padded-text'>{missingContainersCount}</span>
+          </Tooltip>
+        </span>
+      )
     const clusterCapacity = `${size(storageReport.capacity - 
storageReport.remaining)}/${size(storageReport.capacity)}`;
     return (
       <div className='overview-content'>
@@ -272,6 +366,7 @@ export class Overview extends 
React.Component<Record<string, object>, IOverviewS
             <OverviewCard
               hoverable loading={loading} title='Datanodes'
               data={datanodesElement} icon='cluster'
+              error={datanodes === 'N/A'}
               linkToUrl='/Datanodes' />
           </Col>
           <Col xs={24} sm={18} md={12} lg={12} xl={6}>
@@ -290,7 +385,7 @@ export class Overview extends 
React.Component<Record<string, object>, IOverviewS
             <OverviewCard
               loading={loading} title='Containers' data={containersElement}
               icon='container'
-              error={missingContainersCount > 0} linkToUrl={containersLink} />
+              error={missingContainersCount as number > 0 || 
missingContainersCount === 'N/A'} linkToUrl={containersLink} />
           </Col>
           <Col xs={24} sm={18} md={12} lg={12} xl={6}>
             <OverviewCard loading={loading} title='Volumes' 
data={volumes.toString()} icon='inbox' linkToUrl={volumesLink} />
@@ -305,10 +400,22 @@ export class Overview extends 
React.Component<Record<string, object>, IOverviewS
             <OverviewCard loading={loading} title='Deleted Containers' 
data={deletedContainers.toString()} icon='delete' />
           </Col>
           <Col xs={24} sm={18} md={12} lg={12} xl={6} className='summary-font'>
-            <OverviewCard loading={loading} title='Open Keys Summary' 
data={openSummaryData} icon='file-text' linkToUrl='/Om' />
+            <OverviewCard
+              loading={loading}
+              title='Open Keys Summary'
+              data={openSummaryData}
+              icon='file-text'
+              linkToUrl='/Om'
+              error={openKeysError} />
           </Col>
           <Col xs={24} sm={18} md={12} lg={12} xl={6} className='summary-font'>
-            <OverviewCard loading={loading} title='Pending Deleted Keys 
Summary' data={deletePendingSummaryData} icon='delete' linkToUrl='/Om' />
+            <OverviewCard
+              loading={loading}
+              title='Pending Deleted Keys Summary'
+              data={deletePendingSummaryData}
+              icon='delete'
+              linkToUrl='/Om'
+              error={pendingDeleteKeysError} />
           </Col>
           {scmServiceId &&
             <Col xs={24} sm={18} md={12} lg={12} xl={6}>


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

Reply via email to