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

siyao 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 ae59f8ae5f HDDS-7248. Recon: Expand the container status page to show 
all unhealthy container states (#3837)
ae59f8ae5f is described below

commit ae59f8ae5f2149ba1a7749bd3073803345333742
Author: smitajoshi12 <112169209+smitajosh...@users.noreply.github.com>
AuthorDate: Fri Oct 21 12:41:45 2022 +0530

    HDDS-7248. Recon: Expand the container status page to show all unhealthy 
container states (#3837)
---
 .../hadoop/ozone/recon/api/ContainerEndpoint.java  |   1 +
 .../webapps/recon/ozone-recon-web/api/db.json      | 330 ++++++++++++++++++++-
 .../webapps/recon/ozone-recon-web/api/routes.json  |   8 +-
 .../src/components/navBar/navBar.tsx               |   5 +
 .../views/missingContainers/missingContainers.tsx  | 227 +++++++++-----
 5 files changed, 502 insertions(+), 69 deletions(-)

diff --git 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
index 0832700e96..ce8cc70589 100644
--- 
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
+++ 
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java
@@ -242,6 +242,7 @@ public class ContainerEndpoint {
    */
   @GET
   @Path("/missing")
+  @Deprecated
   public Response getMissingContainers(
       @DefaultValue(DEFAULT_FETCH_COUNT) @QueryParam(RECON_QUERY_LIMIT)
       int limit
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
index 04036416f4..1639302e23 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/db.json
@@ -1260,5 +1260,333 @@
       "lastUpdatedTimestamp": 1663421094507,
       "lastUpdatedSeqNumber": 0
     }
-  ]
+  ],
+  "containerUnhealthyMissing": {
+    "missingCount": 0,
+    "underReplicatedCount": 1,
+    "overReplicatedCount": 0,
+    "misReplicatedCount": 0,
+    "containers": [
+      {
+        "containerID": 1,
+        "containerState": "MISSING",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 3,
+        "actualReplicaCount": 0,
+        "replicaDeltaCount": 3,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 2,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_missing1",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_missing2",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_missing3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      },
+      {
+        "containerID": 2,
+        "containerState": "MISSING",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 3,
+        "actualReplicaCount": 0,
+        "replicaDeltaCount": 3,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 3,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_missing1",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_missing2",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_missing3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      }
+    ]
+  },
+  "containerUnhealthyUnderReplicated": {
+    "missingCount": 0,
+    "underReplicatedCount": 1,
+    "overReplicatedCount": 0,
+    "misReplicatedCount": 0,
+    "containers": [
+      {
+        "containerID": 2,
+        "containerState": "UNDER_REPLICATED",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 3,
+        "actualReplicaCount": 2,
+        "replicaDeltaCount": 1,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 2,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_UnderReplicated2",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_underreplicated2",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_underreplicated2",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      },
+      {
+        "containerID": 3,
+        "containerState": "UNDER_REPLICATED",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 4,
+        "actualReplicaCount": 2,
+        "replicaDeltaCount": 2,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 3,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_underreplicated3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_underreplicated3",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_underreplicated3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      }
+    ]
+  },
+  "containerUnhealthyOverReplicated": {
+    "missingCount": 0,
+    "underReplicatedCount": 1,
+    "overReplicatedCount": 0,
+    "misReplicatedCount": 0,
+    "containers": [
+      {
+        "containerID": 2,
+        "containerState": "OVER_REPLICATED",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 3,
+        "actualReplicaCount": 2,
+        "replicaDeltaCount": 1,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 2,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_overreplicated2",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_overreplicated22",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_overreplicated2",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      },
+      {
+        "containerID": 3,
+        "containerState": "OVER_REPLICATED",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 4,
+        "actualReplicaCount": 2,
+        "replicaDeltaCount": 2,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 3,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_overreplicated3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_overreplicated3",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_overreplicated3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      }
+    ]
+  },
+  "containerUnhealthyMisReplicated": {
+    "missingCount": 0,
+    "underReplicatedCount": 1,
+    "overReplicatedCount": 0,
+    "misReplicatedCount": 0,
+    "containers": [
+      {
+        "containerID": 2,
+        "containerState": "MIS_REPLICATED",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 3,
+        "actualReplicaCount": 2,
+        "replicaDeltaCount": 1,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 2,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_misreplicated2",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_misreplicated2",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 2,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_misreplicated2",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      },
+      {
+        "containerID": 3,
+        "containerState": "MIS_REPLICATED",
+        "unhealthySince": 1665590446222,
+        "expectedReplicaCount": 4,
+        "actualReplicaCount": 2,
+        "replicaDeltaCount": 2,
+        "reason": null,
+        "keys": 1,
+        "pipelineID": "a10ffab6-8ed5-414a-aaf5-79890ff3e8a1",
+        "replicas": [
+          {
+            "containerId": 3,
+            "datanodeUuid": "15526f1b-76f2-4d8f-876c-c343c94ea476",
+            "datanodeHost": "ozone_datanode_2.ozone_misreplicated3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590397315,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "f55476ab-4687-464d-a100-1c65de4366e3",
+            "datanodeHost": "ozone_datanode_3.ozone_misreplicated3",
+            "firstSeenTime": 1665588176616,
+            "lastSeenTime": 1665590392293,
+            "lastBcsId": 2
+          },
+          {
+            "containerId": 3,
+            "datanodeUuid": "7a457bcb-d63e-49cc-b3ff-8b22bf48d130",
+            "datanodeHost": "ozone_datanode_1.ozone_misreplicated3",
+            "firstSeenTime": 1665588176660,
+            "lastSeenTime": 1665590272289,
+            "lastBcsId": 0
+          }
+        ]
+      }
+    ]
+  }
 }
\ No newline at end of file
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
index 4aa303fe29..0b0a4bb9d6 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/api/routes.json
@@ -1,7 +1,6 @@
 {
   "/api/v1/*": "/$1",
   "/containers/:id/keys": "/keys",
-  "/containers/missing": "/missingContainers",
   "/utilization/fileCount": "/fileSizeCounts",
   "/namespace/du?path=/&files=true": "/root",
   "/namespace/du?path=/vol:id&files=true": "/volume",
@@ -23,5 +22,10 @@
   "/namespace/du?path=/clunky&files=true": "/clunky",
   "/namespace/summary?path=*": "/metadata",
   "/namespace/quota?path=*": "/quota",
-  "/task/status": "/taskStatus"
+  "/task/status": "/taskStatus",
+  "/containers/missing": "/missingContainers",
+  "/containers/unhealthy/MISSING": "/containerUnhealthyMissing",
+  "/containers/unhealthy/UNDER_REPLICATED": 
"/containerUnhealthyUnderReplicated",
+  "/containers/unhealthy/OVER_REPLICATED": "/containerUnhealthyOverReplicated",
+  "/containers/unhealthy/MIS_REPLICATED": "/containerUnhealthyMisReplicated"
 }
\ No newline at end of file
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
index acc0550404..d381e8e4d4 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/components/navBar/navBar.tsx
@@ -66,6 +66,11 @@ class NavBar extends React.Component<INavBarProps> {
             <span>Pipelines</span>
             <Link to='/Pipelines'/>
           </Menu.Item>
+          <Menu.Item key='/Containers'>
+            <Icon type='container'/>
+            <span>Containers</span>
+            <Link to='/Containers'/>
+          </Menu.Item>
           <Menu.Item key='/Insights'>
             <Icon type='bar-chart'/>
             <span>Insights</span>
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
index 6a6dca304d..c6a76b5b97 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/views/missingContainers/missingContainers.tsx
@@ -18,7 +18,7 @@
 
 import React from 'react';
 import axios from 'axios';
-import {Icon, Table, Tooltip} from 'antd';
+import {Icon, Table, Tooltip, Tabs} from 'antd';
 import {PaginationConfig} from 'antd/lib/pagination';
 import filesize from 'filesize';
 import moment from 'moment';
@@ -26,6 +26,7 @@ import {showDataFetchError, timeFormat} from 'utils/common';
 import './missingContainers.less';
 
 const size = filesize.partial({standard: 'iec'});
+const {TabPane} = Tabs;
 
 interface IMissingContainerResponse {
   containerID: number;
@@ -35,6 +36,19 @@ interface IMissingContainerResponse {
   pipelineID: string;
 }
 
+interface IContainerResponse {
+  containerID: number;
+  containerState: string;
+  unhealthySince: string;
+  expectedReplicaCount: number;
+  actualReplicaCount: number;
+  replicaDeltaCount: number;
+  reason: string;
+  keys: number;
+  pipelineID: string;
+  replicas: IContainerReplicas[];
+}
+
 export interface IContainerReplica {
   containerId: number;
   datanodeHost: string;
@@ -42,11 +56,28 @@ export interface IContainerReplica {
   lastReportTimestamp: number;
 }
 
+export interface IContainerReplicas {
+  containerId: number;
+  datanodeUuid: string;
+  datanodeHost: string;
+  firstSeenTime: number;
+  lastSeenTime: number;
+  lastBcsId: number;
+}
+
 export interface IMissingContainersResponse {
   totalCount: number;
   containers: IMissingContainerResponse[];
 }
 
+interface IUnhealthyContainersResponse {
+  missingCount: number;
+  underReplicatedCount: number;
+  overReplicatedCount: number;
+  misReplicatedCount: number;
+  containers: IContainerResponse[];
+}
+
 interface IKeyResponse {
   Volume: string;
   Bucket: string;
@@ -63,30 +94,79 @@ interface IContainerKeysResponse {
   keys: IKeyResponse[];
 }
 
-const COLUMNS = [
+const KEY_TABLE_COLUMNS = [
+  {
+    title: 'Volume',
+    dataIndex: 'Volume',
+    key: 'Volume'
+  },
+  {
+    title: 'Bucket',
+    dataIndex: 'Bucket',
+    key: 'Bucket'
+  },
+  {
+    title: 'Key',
+    dataIndex: 'Key',
+    key: 'Key'
+  },
+  {
+    title: 'Size',
+    dataIndex: 'DataSize',
+    key: 'DataSize',
+    render: (dataSize: number) => <div>{size(dataSize)}</div>
+  },
+  {
+    title: 'Date Created',
+    dataIndex: 'CreationTime',
+    key: 'CreationTime',
+    render: (date: string) => moment(date).format('lll')
+  },
+  {
+    title: 'Date Modified',
+    dataIndex: 'ModificationTime',
+    key: 'ModificationTime',
+    render: (date: string) => moment(date).format('lll')
+  }
+];
+
+const CONTAINER_TAB_COLUMNS = [
   {
     title: 'Container ID',
     dataIndex: 'containerID',
     key: 'containerID',
-    sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) => 
a.containerID - b.containerID
+    sorter: (a: IContainerResponse, b: IContainerResponse) => a.containerID - 
b.containerID
   },
   {
     title: 'No. of Keys',
     dataIndex: 'keys',
     key: 'keys',
-    sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) => 
a.keys - b.keys
+    sorter: (a: IContainerResponse, b: IContainerResponse) => a.keys - b.keys
+  },
+  {
+    title: 'Active/Expected Replica(s)',
+    dataIndex: 'expectedReplicaCount',
+    key: 'expectedReplicaCount',
+    render: (expectedReplicaCount: number, record: IContainerResponse) => {
+      const actualReplicaCount = record.actualReplicaCount;
+      return (
+        <span>
+          {actualReplicaCount} / {expectedReplicaCount}
+        </span>
+      );
+    }
   },
   {
     title: 'Datanodes',
     dataIndex: 'replicas',
     key: 'replicas',
-    render: (replicas: IContainerReplica[]) => (
+    render: (replicas: IContainerReplicas[]) => (
       <div>
-        {replicas.map(replica => {
+        {replicas && replicas.map(replica => {
           const tooltip = (
             <div>
-              <div>First Report Time: 
{timeFormat(replica.firstReportTimestamp)}</div>
-              <div>Last Report Time: 
{timeFormat(replica.lastReportTimestamp)}</div>
+              <div>First Report Time: {timeFormat(replica.firstSeenTime)}</div>
+              <div>Last Report Time: {timeFormat(replica.lastSeenTime)}</div>
             </div>
           );
           return (
@@ -111,50 +191,14 @@ const COLUMNS = [
     title: 'Pipeline ID',
     dataIndex: 'pipelineID',
     key: 'pipelineID',
-    sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) => 
a.pipelineID.localeCompare(b.pipelineID)
-  },
-  {
-    title: 'Missing Since',
-    dataIndex: 'missingSince',
-    key: 'missingSince',
-    render: (missingSince: number) => timeFormat(missingSince),
-    sorter: (a: IMissingContainerResponse, b: IMissingContainerResponse) => 
a.missingSince - b.missingSince
-  }
-];
-
-const KEY_TABLE_COLUMNS = [
-  {
-    title: 'Volume',
-    dataIndex: 'Volume',
-    key: 'Volume'
-  },
-  {
-    title: 'Bucket',
-    dataIndex: 'Bucket',
-    key: 'Bucket'
-  },
-  {
-    title: 'Key',
-    dataIndex: 'Key',
-    key: 'Key'
-  },
-  {
-    title: 'Size',
-    dataIndex: 'DataSize',
-    key: 'DataSize',
-    render: (dataSize: number) => <div>{size(dataSize)}</div>
+    sorter: (a: IContainerResponse, b: IContainerResponse) => 
a.pipelineID.localeCompare(b.pipelineID)
   },
   {
-    title: 'Date Created',
-    dataIndex: 'CreationTime',
-    key: 'CreationTime',
-    render: (date: string) => moment(date).format('lll')
-  },
-  {
-    title: 'Date Modified',
-    dataIndex: 'ModificationTime',
-    key: 'ModificationTime',
-    render: (date: string) => moment(date).format('lll')
+    title: 'Unhealthy Since',
+    dataIndex: 'unhealthySince',
+    key: 'unhealthySince',
+    render: (unhealthySince: number) => timeFormat(unhealthySince),
+    sorter: (a: IContainerResponse, b: IContainerResponse) => a.unhealthySince 
- b.unhealthySince
   }
 ];
 
@@ -171,7 +215,10 @@ interface IExpandedRowState {
 
 interface IMissingContainersState {
   loading: boolean;
-  dataSource: IMissingContainerResponse[];
+  missingDataSource: IContainerResponse[];
+  underReplicatedDataSource: IContainerResponse[];
+  overReplicatedDataSource: IContainerResponse[];
+  misReplicatedDataSource: IContainerResponse[];
   totalCount: number;
   expandedRowData: IExpandedRow;
 }
@@ -181,7 +228,10 @@ export class MissingContainers extends 
React.Component<Record<string, object>, I
     super(props);
     this.state = {
       loading: false,
-      dataSource: [],
+      missingDataSource: [],
+      underReplicatedDataSource: [],
+      overReplicatedDataSource: [],
+      misReplicatedDataSource: [],
       totalCount: 0,
       expandedRowData: {}
     };
@@ -192,16 +242,36 @@ export class MissingContainers extends 
React.Component<Record<string, object>, I
     this.setState({
       loading: true
     });
-    axios.get('/api/v1/containers/missing').then(response => {
-      const missingContainersResponse: IMissingContainersResponse = 
response.data;
-      const totalCount = missingContainersResponse.totalCount;
-      const missingContainers: IMissingContainerResponse[] = 
missingContainersResponse.containers;
+
+    axios.all([
+      axios.get('/api/v1/containers/unhealthy/MISSING'),
+      axios.get('/api/v1/containers/unhealthy/UNDER_REPLICATED'),
+      axios.get('/api/v1/containers/unhealthy/OVER_REPLICATED'),
+      axios.get('/api/v1/containers/unhealthy/MIS_REPLICATED')
+    ]).then(axios.spread((missingContainersResponse, underReplicatedResponse, 
overReplicatedResponse, misReplicatedResponse, allReplicatedResponse) => {
+
+      const missingContainersResponseData: IUnhealthyContainersResponse = 
missingContainersResponse.data;
+      const totalCount = missingContainersResponseData.missingCount;
+      const missingContainers: IContainerResponse[] = 
missingContainersResponseData.containers;
+
+      const underReplicatedResponseData: IUnhealthyContainersResponse = 
underReplicatedResponse.data;
+      const uContainers: IContainerResponse[] = 
underReplicatedResponseData.containers;
+      
+      const overReplicatedResponseData: IUnhealthyContainersResponse = 
overReplicatedResponse.data;
+      const oContainers: IContainerResponse[] = 
overReplicatedResponseData.containers;
+      
+      const misReplicatedResponseData: IUnhealthyContainersResponse = 
misReplicatedResponse.data;
+      const mContainers: IContainerResponse[] = 
misReplicatedResponseData.containers;
+ 
       this.setState({
         loading: false,
-        dataSource: missingContainers,
+        missingDataSource: missingContainers,
+        underReplicatedDataSource: uContainers,
+        overReplicatedDataSource: oContainers,
+        misReplicatedDataSource: mContainers,
         totalCount
       });
-    }).catch(error => {
+    })).catch(error => {
       this.setState({
         loading: false
       });
@@ -212,7 +282,7 @@ export class MissingContainers extends 
React.Component<Record<string, object>, I
   onShowSizeChange = (current: number, pageSize: number) => {
     console.log(current, pageSize);
   };
-
+  
   onRowExpandClick = (expanded: boolean, record: IMissingContainerResponse) => 
{
     if (expanded) {
       this.setState(({expandedRowData}) => {
@@ -270,7 +340,7 @@ export class MissingContainers extends 
React.Component<Record<string, object>, I
   };
 
   render() {
-    const {dataSource, loading, totalCount} = this.state;
+    const {missingDataSource, loading, underReplicatedDataSource, 
overReplicatedDataSource, misReplicatedDataSource} = this.state;
     const paginationConfig: PaginationConfig = {
       showTotal: (total: number, range) => `${range[0]}-${range[1]} of 
${total} missing containers`,
       showSizeChanger: true,
@@ -279,14 +349,39 @@ export class MissingContainers extends 
React.Component<Record<string, object>, I
     return (
       <div className='missing-containers-container'>
         <div className='page-header'>
-          Missing Containers ({totalCount})
+          Containers
         </div>
         <div className='content-div'>
-          <Table
-            expandRowByClick dataSource={dataSource} columns={COLUMNS}
-            loading={loading}
-            pagination={paginationConfig} rowKey='containerID'
-            expandedRowRender={this.expandedRowRender} 
onExpand={this.onRowExpandClick}/>
+          <Tabs defaultActiveKey='1'>
+            <TabPane key='1' tab="Missing">
+              <Table
+                expandRowByClick dataSource={missingDataSource} 
columns={CONTAINER_TAB_COLUMNS}
+                loading={loading}
+                pagination={paginationConfig} rowKey='containerID'
+                expandedRowRender={this.expandedRowRender} 
onExpand={this.onRowExpandClick}/>
+            </TabPane>
+            <TabPane key='2' tab='Under-Replicated'>
+              <Table
+                expandRowByClick dataSource={underReplicatedDataSource} 
columns={CONTAINER_TAB_COLUMNS}
+                loading={loading}
+                pagination={paginationConfig} rowKey='containerID'
+                expandedRowRender={this.expandedRowRender} 
onExpand={this.onRowExpandClick}/>
+            </TabPane>
+            <TabPane key='3' tab='Over-Replicated'>
+              <Table
+                expandRowByClick dataSource={overReplicatedDataSource} 
columns={CONTAINER_TAB_COLUMNS}
+                loading={loading}
+                pagination={paginationConfig} rowKey='containerID'
+                expandedRowRender={this.expandedRowRender} 
onExpand={this.onRowExpandClick}/>
+            </TabPane>
+            <TabPane key='4' tab='Mis-Replicated'>
+              <Table
+                expandRowByClick dataSource={misReplicatedDataSource} 
columns={CONTAINER_TAB_COLUMNS}
+                loading={loading}
+                pagination={paginationConfig} rowKey='containerID'
+                expandedRowRender={this.expandedRowRender} 
onExpand={this.onRowExpandClick}/>
+            </TabPane>
+          </Tabs>
         </div>
       </div>
     );


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@ozone.apache.org
For additional commands, e-mail: commits-h...@ozone.apache.org

Reply via email to