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 877504aee1 HDDS-11156. Improve Buckets page UI (#7100)
877504aee1 is described below

commit 877504aee1a5a23eeaa097e159b033018af66c86
Author: Abhishek Pal <[email protected]>
AuthorDate: Tue Sep 3 17:38:26 2024 +0530

    HDDS-11156. Improve Buckets page UI (#7100)
---
 .../webapps/recon/ozone-recon-web/pnpm-lock.yaml   | 134 ++---
 .../src/v2/components/search/search.tsx            |   4 +
 .../src/v2/components/select/multiSelect.tsx       |  56 +-
 .../src/v2/components/select/singleSelect.tsx      |   4 +-
 .../src/v2/pages/buckets/buckets.less              |  41 ++
 .../src/v2/pages/buckets/buckets.tsx               | 563 +++++++++++++++++++++
 .../src/v2/pages/volumes/volumes.tsx               |   8 +-
 .../recon/ozone-recon-web/src/v2/routes-v2.tsx     |   5 +
 .../ozone-recon-web/src/v2/types/bucket.types.ts   |  20 +-
 9 files changed, 742 insertions(+), 93 deletions(-)

diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/pnpm-lock.yaml
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/pnpm-lock.yaml
index ebbc4e2219..3c472d5f79 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/pnpm-lock.yaml
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/pnpm-lock.yaml
@@ -153,7 +153,7 @@ packages:
     dependencies:
       '@ant-design/colors': 6.0.0
       '@ant-design/icons-svg': 4.4.2
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       lodash: 4.17.21
       rc-util: 5.43.0([email protected])([email protected])
@@ -166,7 +166,7 @@ packages:
     peerDependencies:
       react: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       json2mq: 0.2.0
       lodash: 4.17.21
@@ -187,11 +187,11 @@ packages:
       '@babel/highlight': 7.24.7
       picocolors: 1.0.1
 
-  /@babel/[email protected]:
-    resolution: {integrity: 
sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==}
+  /@babel/[email protected]:
+    resolution: {integrity: 
sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.25.4
+      '@babel/types': 7.25.6
       '@jridgewell/gen-mapping': 0.3.5
       '@jridgewell/trace-mapping': 0.3.25
       jsesc: 2.5.2
@@ -201,8 +201,8 @@ packages:
     resolution: {integrity: 
sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/traverse': 7.25.4
-      '@babel/types': 7.25.4
+      '@babel/traverse': 7.25.6
+      '@babel/types': 7.25.6
     transitivePeerDependencies:
       - supports-color
     dev: false
@@ -225,16 +225,16 @@ packages:
       js-tokens: 4.0.0
       picocolors: 1.0.1
 
-  /@babel/[email protected]:
-    resolution: {integrity: 
sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==}
+  /@babel/[email protected]:
+    resolution: {integrity: 
sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==}
     engines: {node: '>=6.0.0'}
     hasBin: true
     dependencies:
-      '@babel/types': 7.25.4
+      '@babel/types': 7.25.6
     dev: false
 
-  /@babel/[email protected]:
-    resolution: {integrity: 
sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==}
+  /@babel/[email protected]:
+    resolution: {integrity: 
sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
       regenerator-runtime: 0.14.1
@@ -244,27 +244,27 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/code-frame': 7.24.7
-      '@babel/parser': 7.25.4
-      '@babel/types': 7.25.4
+      '@babel/parser': 7.25.6
+      '@babel/types': 7.25.6
     dev: false
 
-  /@babel/[email protected]:
-    resolution: {integrity: 
sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==}
+  /@babel/[email protected]:
+    resolution: {integrity: 
sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/code-frame': 7.24.7
-      '@babel/generator': 7.25.5
-      '@babel/parser': 7.25.4
+      '@babel/generator': 7.25.6
+      '@babel/parser': 7.25.6
       '@babel/template': 7.25.0
-      '@babel/types': 7.25.4
+      '@babel/types': 7.25.6
       debug: 4.3.6
       globals: 11.12.0
     transitivePeerDependencies:
       - supports-color
     dev: false
 
-  /@babel/[email protected]:
-    resolution: {integrity: 
sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==}
+  /@babel/[email protected]:
+    resolution: {integrity: 
sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==}
     engines: {node: '>=6.9.0'}
     dependencies:
       '@babel/helper-string-parser': 7.24.8
@@ -295,7 +295,7 @@ packages:
     peerDependencies:
       react: '>=16.3.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       '@emotion/cache': 10.0.29
       '@emotion/css': 10.0.27
       '@emotion/serialize': 0.11.16
@@ -1186,7 +1186,7 @@ packages:
     engines: {node: '>=12'}
     dependencies:
       '@babel/code-frame': 7.24.7
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       '@types/aria-query': 5.0.4
       aria-query: 5.1.3
       chalk: 4.1.2
@@ -1215,7 +1215,7 @@ packages:
       react: <18.0.0
       react-dom: <18.0.0
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       '@testing-library/dom': 8.20.1
       '@types/react-dom': 16.8.4
       react: 16.14.0
@@ -1674,7 +1674,7 @@ packages:
       '@ant-design/colors': 5.1.1
       '@ant-design/icons': 4.8.3([email protected])([email protected])
       '@ant-design/react-slick': 0.28.4([email protected])
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       array-tree-filter: 2.1.0
       classnames: 2.5.1
       copy-to-clipboard: 3.3.3
@@ -1853,7 +1853,7 @@ packages:
   /[email protected]:
     resolution: {integrity: 
sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==}
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       cosmiconfig: 6.0.0
       resolve: 1.22.8
     dev: false
@@ -2370,7 +2370,7 @@ packages:
     resolution: {integrity: 
sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
     engines: {node: '>=0.11'}
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
     dev: false
 
   /[email protected]:
@@ -2547,7 +2547,7 @@ packages:
   /[email protected]:
     resolution: {integrity: 
sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       csstype: 3.1.3
     dev: false
 
@@ -3514,7 +3514,7 @@ packages:
   /[email protected]:
     resolution: {integrity: 
sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       loose-envify: 1.4.0
       resolve-pathname: 3.0.0
       tiny-invariant: 1.3.3
@@ -5088,7 +5088,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       dom-align: 1.12.4
       rc-util: 5.43.0([email protected])([email protected])
@@ -5103,7 +5103,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       array-tree-filter: 2.1.0
       rc-trigger: 5.3.4([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5118,7 +5118,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       react: 16.14.0
       react-dom: 16.14.0([email protected])
@@ -5130,7 +5130,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-motion: 2.9.2([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5145,7 +5145,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-motion: 2.9.2([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5159,7 +5159,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5172,7 +5172,7 @@ packages:
       react: '*'
       react-dom: '*'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-trigger: 5.3.4([email protected])([email protected])
       react: 16.14.0
@@ -5186,7 +5186,7 @@ packages:
       react: '>= 16.9.0'
       react-dom: '>= 16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       async-validator: 3.5.2
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5199,7 +5199,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-dialog: 8.5.3([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5213,7 +5213,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5226,7 +5226,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-menu: 8.10.8([email protected])([email protected])
       rc-textarea: 0.3.7([email protected])([email protected])
@@ -5242,7 +5242,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       mini-store: 3.0.6([email protected])([email protected])
       rc-motion: 2.9.2([email protected])([email protected])
@@ -5260,7 +5260,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5274,7 +5274,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-motion: 2.9.2([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5288,7 +5288,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-resize-observer: 1.4.0([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5302,7 +5302,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       react: 16.14.0
       react-dom: 16.14.0([email protected])
@@ -5315,7 +5315,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       date-fns: 2.30.0
       dayjs: 1.11.13
@@ -5333,7 +5333,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       react: 16.14.0
       react-dom: 16.14.0([email protected])
@@ -5346,7 +5346,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5359,7 +5359,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5374,7 +5374,7 @@ packages:
       react: '*'
       react-dom: '*'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-motion: 2.9.2([email protected])([email protected])
       rc-overflow: 1.3.2([email protected])([email protected])
@@ -5392,7 +5392,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-tooltip: 5.0.2([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5408,7 +5408,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5421,7 +5421,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5435,7 +5435,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-resize-observer: 1.4.0([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5451,7 +5451,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-dropdown: 3.2.5([email protected])([email protected])
       rc-menu: 8.10.8([email protected])([email protected])
@@ -5467,7 +5467,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-resize-observer: 1.4.0([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5482,7 +5482,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       rc-trigger: 5.3.4([email protected])([email protected])
       react: 16.14.0
       react-dom: 16.14.0([email protected])
@@ -5494,7 +5494,7 @@ packages:
       react: '*'
       react-dom: '*'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-select: 12.1.13([email protected])([email protected])
       rc-tree: 4.1.5([email protected])([email protected])
@@ -5510,7 +5510,7 @@ packages:
       react: '*'
       react-dom: '*'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-motion: 2.9.2([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5526,7 +5526,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-align: 4.0.15([email protected])([email protected])
       rc-motion: 2.9.2([email protected])([email protected])
@@ -5541,7 +5541,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-util: 5.43.0([email protected])([email protected])
       react: 16.14.0
@@ -5554,7 +5554,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       react: 16.14.0
       react-dom: 16.14.0([email protected])
       react-is: 18.3.1
@@ -5567,7 +5567,7 @@ packages:
       react: '>=16.9.0'
       react-dom: '>=16.9.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       classnames: 2.5.1
       rc-resize-observer: 1.4.0([email protected])([email protected])
       rc-util: 5.43.0([email protected])([email protected])
@@ -5620,7 +5620,7 @@ packages:
     peerDependencies:
       react: '>=15'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       history: 4.10.1
       loose-envify: 1.4.0
       prop-types: 15.8.1
@@ -5635,7 +5635,7 @@ packages:
     peerDependencies:
       react: '>=15'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       history: 4.10.1
       hoist-non-react-statics: 3.3.2
       loose-envify: 1.4.0
@@ -5653,7 +5653,7 @@ packages:
       react: ^16.8.0 || ^17.0.0
       react-dom: ^16.8.0 || ^17.0.0
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       '@emotion/cache': 10.0.29
       '@emotion/core': 10.3.1([email protected])
       '@emotion/css': 10.0.27
@@ -5673,7 +5673,7 @@ packages:
       react: '>=16.6.0'
       react-dom: '>=16.6.0'
     dependencies:
-      '@babel/runtime': 7.25.4
+      '@babel/runtime': 7.25.6
       dom-helpers: 5.2.1
       loose-envify: 1.4.0
       prop-types: 15.8.1
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/search/search.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/search/search.tsx
index 21d4341787..8cac2a9c04 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/search/search.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/search/search.tsx
@@ -23,6 +23,7 @@ import { Option } from '@/v2/components/select/singleSelect';
 
 // ------------- Types -------------- //
 type SearchProps = {
+  disabled?: boolean;
   searchColumn?: string;
   searchInput: string;
   searchOptions?: Option[];
@@ -39,6 +40,7 @@ type SearchProps = {
 
 // ------------- Component -------------- //
 const Search: React.FC<SearchProps> = ({
+  disabled = false,
   searchColumn,
   searchInput = '',
   searchOptions = [],
@@ -48,6 +50,7 @@ const Search: React.FC<SearchProps> = ({
 
   const selectFilter = searchColumn
     ? (<Select
+      disabled={disabled}
       defaultValue={searchColumn}
       options={searchOptions}
       onChange={onChange} />)
@@ -55,6 +58,7 @@ const Search: React.FC<SearchProps> = ({
 
   return (
     <Input
+      disabled={disabled}
       placeholder='Enter Search text'
       allowClear={true}
       value={searchInput}
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/multiSelect.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/multiSelect.tsx
index 7a6b494aae..07b3f9eafa 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/multiSelect.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/multiSelect.tsx
@@ -22,7 +22,8 @@ import {
   Props as ReactSelectProps,
   components,
   OptionProps,
-  ValueType
+  ValueType,
+  ValueContainerProps
 } from 'react-select';
 
 import { selectStyles } from "@/v2/constants/select.constants";
@@ -45,6 +46,27 @@ interface MultiSelectProps extends ReactSelectProps<Option, 
true> {
 }
 
 // ------------- Component -------------- //
+
+const Option: React.FC<OptionProps<Option, true>> = (props) => {
+  return (
+    <div>
+      <components.Option
+        {...props}>
+        <input
+          type='checkbox'
+          checked={props.isSelected}
+          style={{
+            marginRight: '8px',
+            accentColor: '#1AA57A'
+          }}
+          onChange={() => null} />
+        <label>{props.label}</label>
+      </components.Option>
+    </div>
+  )
+}
+
+
 const MultiSelect: React.FC<MultiSelectProps> = ({
   options = [],
   selected = [],
@@ -58,24 +80,20 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
   ...props
 }) => {
 
-  const Option: React.FC<OptionProps<Option, true>> = (props) => {
+  const ValueContainer = ({ children, ...props }: ValueContainerProps<Option, 
true>) => {
     return (
-      <div>
-        <components.Option
-          {...props}>
-          <input
-            type='checkbox'
-            checked={props.isSelected}
-            style={{
-              marginRight: '8px',
-              accentColor: '#1AA57A'
-            }}
-            onChange={() => null} />
-          <label>{props.label}</label>
-        </components.Option>
-      </div>
-    )
-  }
+      <components.ValueContainer {...props}>
+        {React.Children.map(children, (child) => (
+          ((child as React.ReactElement<any, string
+            | React.JSXElementConstructor<any>>
+            | React.ReactPortal)?.type as 
React.JSXElementConstructor<any>)).name === "DummyInput"
+          ? child
+          : null
+        )}
+        {placeholder}: {selected.length} selected
+      </components.ValueContainer>
+    );
+  };
 
   return (
     <ReactSelect
@@ -89,10 +107,12 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
     classNamePrefix='multi-select'
     options={options}
     components={{
+      ValueContainer,
       Option
     }}
     placeholder={placeholder}
     value={selected}
+    isOptionDisabled={(option) => option.value === fixedColumn}
     onChange={(selected: ValueType<Option, true>) => {
       if (selected?.length === options.length) return onChange!(options);
       return onChange!(selected);
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/singleSelect.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/singleSelect.tsx
index 41ab03f598..1d02b40733 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/singleSelect.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/components/select/singleSelect.tsx
@@ -50,7 +50,7 @@ const SingleSelect: React.FC<SingleSelectProps> = ({
 
 
   const ValueContainer = ({ children, ...props }: ValueContainerProps<Option, 
false>) => {
-    const selectedLimit = props.getValue() as Option[];
+    const selectedValue = props.getValue() as Option[];
     return (
       <components.ValueContainer {...props}>
         {React.Children.map(children, (child) => (
@@ -60,7 +60,7 @@ const SingleSelect: React.FC<SingleSelectProps> = ({
           ? child
           : null
         )}
-        Limit: {selectedLimit[0]?.label ?? ''}
+        {placeholder}: {selectedValue[0]?.label ?? ''}
       </components.ValueContainer>
     );
   };
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.less
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.less
new file mode 100644
index 0000000000..8f4c8ffaf9
--- /dev/null
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.less
@@ -0,0 +1,41 @@
+/*
+* 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.
+*/
+
+.content-div {
+  min-height: unset;
+
+  .table-header-section {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .table-filter-section {
+      font-size: 14px;
+      font-weight: normal;
+      display: flex;
+      column-gap: 8px;
+      padding: 16px 8px;
+    }
+  }
+
+  .tag-block {
+    display: flex;
+    column-gap: 8px;
+    padding: 0px 8px 16px 8px;
+  }
+}
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
new file mode 100644
index 0000000000..bd8950e54c
--- /dev/null
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/pages/buckets/buckets.tsx
@@ -0,0 +1,563 @@
+/*
+ * 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 React, { useEffect, useState } from 'react';
+import moment from 'moment';
+import { Table, Tag } from 'antd';
+import {
+  ColumnProps,
+  ColumnsType,
+  TablePaginationConfig
+} from 'antd/es/table';
+import {
+  CheckCircleOutlined,
+  CloseCircleOutlined,
+  CloudServerOutlined,
+  FileUnknownOutlined,
+  HddOutlined,
+  LaptopOutlined,
+  SaveOutlined
+} from '@ant-design/icons';
+import { ValueType } from 'react-select';
+import { useLocation } from 'react-router-dom';
+
+import QuotaBar from '@/components/quotaBar/quotaBar';
+import AutoReloadPanel from '@/components/autoReloadPanel/autoReloadPanel';
+import AclPanel from '@/v2/components/aclDrawer/aclDrawer';
+import Search from '@/v2/components/search/search';
+import MultiSelect from '@/v2/components/select/multiSelect';
+import SingleSelect, { Option } from '@/v2/components/select/singleSelect';
+
+import { AutoReloadHelper } from '@/utils/autoReloadHelper';
+import { AxiosGetHelper } from "@/utils/axiosRequestHelper";
+import { nullAwareLocaleCompare, showDataFetchError } from '@/utils/common';
+import { useDebounce } from '@/v2/hooks/debounce.hook';
+
+import {
+  Bucket,
+  BucketLayout,
+  BucketLayoutTypeList,
+  BucketResponse,
+  BucketsState,
+  BucketStorage,
+  BucketStorageTypeList
+} from '@/v2/types/bucket.types';
+
+import './buckets.less';
+
+
+const LIMIT_OPTIONS: Option[] = [
+  {
+    label: '1000',
+    value: '1000'
+  },
+  {
+    label: '5000',
+    value: '5000'
+  },
+  {
+    label: '10000',
+    value: '10000'
+  },
+  {
+    label: '20000',
+    value: '20000'
+  }
+]
+
+const renderIsVersionEnabled = (isVersionEnabled: boolean) => {
+  return isVersionEnabled
+    ? <CheckCircleOutlined
+      style={{ color: '#1da57a' }}
+      className='icon-success' />
+    : <CloseCircleOutlined className='icon-neutral' />
+};
+
+const renderStorageType = (bucketStorage: BucketStorage) => {
+  const bucketStorageIconMap: Record<BucketStorage, React.ReactElement> = {
+    RAM_DISK: <LaptopOutlined />,
+    SSD: <SaveOutlined />,
+    DISK: <HddOutlined />,
+    ARCHIVE: <CloudServerOutlined />
+  };
+  const icon = bucketStorage in bucketStorageIconMap
+    ? bucketStorageIconMap[bucketStorage]
+    : <FileUnknownOutlined />;
+  return <span>{icon} {bucketStorage}</span>;
+};
+
+const renderBucketLayout = (bucketLayout: BucketLayout) => {
+  const bucketLayoutColorMap = {
+    FILE_SYSTEM_OPTIMIZED: 'green',
+    OBJECT_STORE: 'orange',
+    LEGACY: 'blue'
+  };
+  const color = bucketLayout in bucketLayoutColorMap ?
+    bucketLayoutColorMap[bucketLayout] : '';
+  return <Tag color={color}>{bucketLayout}</Tag>;
+};
+
+const SearchableColumnOpts = [{
+  label: 'Bucket',
+  value: 'name'
+}, {
+  label: 'Volume',
+  value: 'volumeName'
+}]
+
+const COLUMNS: ColumnsType<Bucket> = [
+  {
+    title: 'Bucket',
+    dataIndex: 'name',
+    key: 'name',
+    sorter: (a: Bucket, b: Bucket) => a.name.localeCompare(b.name),
+    defaultSortOrder: 'ascend' as const
+  },
+  {
+    title: 'Volume',
+    dataIndex: 'volumeName',
+    key: 'volumeName',
+    sorter: (a: Bucket, b: Bucket) => a.volumeName.localeCompare(b.volumeName),
+    defaultSortOrder: 'ascend' as const
+  },
+  {
+    title: 'Owner',
+    dataIndex: 'owner',
+    key: 'owner',
+    sorter: (a: Bucket, b: Bucket) => nullAwareLocaleCompare(a.owner, b.owner)
+  },
+  {
+    title: 'Versioning',
+    dataIndex: 'versioning',
+    key: 'isVersionEnabled',
+    render: (isVersionEnabled: boolean) => 
renderIsVersionEnabled(isVersionEnabled)
+  },
+  {
+    title: 'Storage Type',
+    dataIndex: 'storageType',
+    key: 'storageType',
+    filterMultiple: true,
+    filters: BucketStorageTypeList.map(state => ({ text: state, value: state 
})),
+    onFilter: (value, record: Bucket) => record.storageType === value,
+    sorter: (a: Bucket, b: Bucket) => 
a.storageType.localeCompare(b.storageType),
+    render: (storageType: BucketStorage) => renderStorageType(storageType)
+  },
+  {
+    title: 'Bucket Layout',
+    dataIndex: 'bucketLayout',
+    key: 'bucketLayout',
+    filterMultiple: true,
+    filters: BucketLayoutTypeList.map(state => ({ text: state, value: state 
})),
+    onFilter: (value, record: Bucket) => record.bucketLayout === value,
+    sorter: (a: Bucket, b: Bucket) => 
a.bucketLayout.localeCompare(b.bucketLayout),
+    render: (bucketLayout: BucketLayout) => renderBucketLayout(bucketLayout)
+  },
+  {
+    title: 'Creation Time',
+    dataIndex: 'creationTime',
+    key: 'creationTime',
+    sorter: (a: Bucket, b: Bucket) => a.creationTime - b.creationTime,
+    render: (creationTime: number) => {
+      return creationTime > 0 ? moment(creationTime).format('ll LTS') : 'NA';
+    }
+  },
+  {
+    title: 'Modification Time',
+    dataIndex: 'modificationTime',
+    key: 'modificationTime',
+    sorter: (a: Bucket, b: Bucket) => a.modificationTime - b.modificationTime,
+    render: (modificationTime: number) => {
+      return modificationTime > 0 ? moment(modificationTime).format('ll LTS') 
: 'NA';
+    }
+  },
+  {
+    title: 'Storage Capacity',
+    key: 'quotaCapacityBytes',
+    sorter: (a: Bucket, b: Bucket) => a.usedBytes - b.usedBytes,
+    render: (text: string, record: Bucket) => (
+      <QuotaBar
+        quota={record.quotaInBytes}
+        used={record.usedBytes}
+        quotaType='size'
+      />
+    )
+  },
+  {
+    title: 'Namespace Capacity',
+    key: 'namespaceCapacity',
+    sorter: (a: Bucket, b: Bucket) => a.usedNamespace - b.usedNamespace,
+    render: (text: string, record: Bucket) => (
+      <QuotaBar
+        quota={record.quotaInNamespace}
+        used={record.usedNamespace}
+        quotaType='namespace'
+      />
+    )
+  },
+  {
+    title: 'Source Volume',
+    dataIndex: 'sourceVolume',
+    key: 'sourceVolume',
+    render: (sourceVolume: string) => {
+      return sourceVolume ? sourceVolume : 'NA';
+    }
+  },
+  {
+    title: 'Source Bucket',
+    dataIndex: 'sourceBucket',
+    key: 'sourceBucket',
+    render: (sourceBucket: string) => {
+      return sourceBucket ? sourceBucket : 'NA';
+    }
+  }
+];
+
+const defaultColumns = COLUMNS.map(column => ({
+  label: column.title as string,
+  value: column.key as string
+}));
+
+function getVolumeBucketMap(data: Bucket[]) {
+  const volumeBucketMap = data.reduce((
+    map: Map<string, Set<Bucket>>,
+    currentBucket
+  ) => {
+    const volume = currentBucket.volumeName;
+    if (map.has(volume)) {
+      const buckets = Array.from(map.get(volume)!);
+      map.set(volume, new Set([...buckets, currentBucket]));
+    } else {
+      map.set(volume, new Set<Bucket>().add(currentBucket));
+    }
+    return map;
+  }, new Map<string, Set<Bucket>>());
+  return volumeBucketMap;
+}
+
+function getFilteredBuckets(
+  selectedVolumes: Option[],
+  bucketsMap: Map<string, Set<Bucket>>
+) {
+  let selectedBuckets: Bucket[] = [];
+  selectedVolumes.forEach(selectedVolume => {
+    if (bucketsMap.has(selectedVolume.value)
+      && bucketsMap.get(selectedVolume.value)) {
+      selectedBuckets = [
+        ...selectedBuckets,
+        ...Array.from(bucketsMap.get(selectedVolume.value)!)
+      ];
+    }
+  });
+
+  return selectedBuckets;
+}
+
+const Buckets: React.FC<{}> = () => {
+
+  let cancelSignal: AbortController;
+
+  const [state, setState] = useState<BucketsState>({
+    totalCount: 0,
+    lastUpdated: 0,
+    columnOptions: defaultColumns,
+    volumeBucketMap: new Map<string, Set<Bucket>>(),
+    bucketsUnderVolume: [],
+    volumeOptions: [],
+  });
+  const [loading, setLoading] = useState<boolean>(false);
+  const [selectedColumns, setSelectedColumns] = 
useState<Option[]>(defaultColumns);
+  const [selectedVolumes, setSelectedVolumes] = useState<Option[]>([]);
+  const [selectedLimit, setSelectedLimit] = useState<Option>(LIMIT_OPTIONS[0]);
+  const [searchTerm, setSearchTerm] = useState<string>('');
+  const [showPanel, setShowPanel] = useState<boolean>(false);
+  const [searchColumn, setSearchColumn] = useState<'name' | 
'volumeName'>('name');
+  const [currentRow, setCurrentRow] = useState<Bucket | Record<string, 
never>>({})
+
+  const debouncedSearch = useDebounce(searchTerm, 300);
+  const { search } = useLocation();
+
+  const paginationConfig: TablePaginationConfig = {
+    showTotal: (total: number, range) => `${range[0]}-${range[1]} of ${total} 
buckets`,
+    showSizeChanger: true
+  };
+
+  function getVolumeSearchParam() {
+    return new URLSearchParams(search).get('volume');
+  };
+
+  function getFilteredData(data: Bucket[]) {
+    return data.filter(
+      (bucket: Bucket) => bucket[searchColumn].includes(debouncedSearch)
+    );
+  }
+
+  function handleVolumeChange(selected: ValueType<Option, true>) {
+    const { volumeBucketMap } = state;
+    const volumeSelections = (selected as Option[]);
+    let selectedBuckets: Bucket[] = [];
+
+    if (volumeSelections?.length > 0) {
+      selectedBuckets = getFilteredBuckets(volumeSelections, volumeBucketMap)
+    }
+
+    setSelectedVolumes(volumeSelections);
+    setState({
+      ...state,
+      bucketsUnderVolume: selectedBuckets
+    });
+  };
+
+  function handleAclLinkClick(bucket: Bucket) {
+    setCurrentRow(bucket);
+    setShowPanel(true);
+  }
+
+  function filterSelectedColumns() {
+    const columnKeys = selectedColumns.map((column) => column.value);
+    return COLUMNS.filter(
+      (column) => columnKeys.indexOf(column.key as string) >= 0
+    )
+  }
+
+  function addAclColumn() {
+    // Inside the class component to access the React internal state
+    const aclLinkColumn: ColumnProps<Bucket> = {
+      title: 'ACLs',
+      dataIndex: 'acls',
+      key: 'acls',
+      render: (_: any, record: Bucket) => {
+        return (
+          <a
+            key='acl'
+            onClick={() => {
+              handleAclLinkClick(record);
+            }}
+          >
+            Show ACL
+          </a>
+        );
+      }
+    };
+
+    if (COLUMNS.length > 0 && COLUMNS[COLUMNS.length - 1].key !== 'acls') {
+      // Push the ACL column for initial
+      COLUMNS.push(aclLinkColumn);
+    } else {
+      // Replace old ACL column with new ACL column with correct reference
+      // e.g. After page is reloaded / redirect from other page
+      COLUMNS[COLUMNS.length - 1] = aclLinkColumn;
+    }
+
+    if (defaultColumns.length > 0 && defaultColumns[defaultColumns.length - 
1].label !== 'acls') {
+      defaultColumns.push({
+        label: aclLinkColumn.title as string,
+        value: aclLinkColumn.key as string
+      });
+    }
+  };
+
+  function handleColumnChange(selected: ValueType<Option, true>) {
+    setSelectedColumns(selected as Option[]);
+  }
+
+  function handleLimitChange(selected: ValueType<Option, false>) {
+    setSelectedLimit(selected as Option);
+  }
+
+  const loadData = () => {
+    setLoading(true);
+    const { request, controller } = AxiosGetHelper(
+      '/api/v1/buckets',
+      cancelSignal,
+      '',
+      { limit: selectedLimit.value }
+    );
+    cancelSignal = controller;
+    request.then(response => {
+      const bucketsResponse: BucketResponse = response.data;
+      const totalCount = bucketsResponse.totalCount;
+      const buckets: Bucket[] = bucketsResponse.buckets;
+
+      const dataSource: Bucket[] = buckets?.map(bucket => {
+        return {
+          volumeName: bucket.volumeName,
+          name: bucket.name,
+          versioning: bucket.versioning,
+          storageType: bucket.storageType,
+          bucketLayout: bucket.bucketLayout,
+          creationTime: bucket.creationTime,
+          modificationTime: bucket.modificationTime,
+          sourceVolume: bucket.sourceVolume,
+          sourceBucket: bucket.sourceBucket,
+          usedBytes: bucket.usedBytes,
+          usedNamespace: bucket.usedNamespace,
+          quotaInBytes: bucket.quotaInBytes,
+          quotaInNamespace: bucket.quotaInNamespace,
+          owner: bucket.owner,
+          acls: bucket.acls
+        };
+      }) ?? [];
+
+      const volumeBucketMap: Map<string, Set<Bucket>> = 
getVolumeBucketMap(dataSource);
+
+      // Set options for volume selection dropdown
+      const volumeOptions: Option[] = Array.from(
+        volumeBucketMap.keys()
+      ).map(k => ({
+        label: k,
+        value: k
+      }));
+
+      setLoading(false);
+
+      setSelectedVolumes((prevState) => {
+        if (prevState.length === 0) return volumeOptions;
+        return prevState;
+      });
+
+      setState({
+        ...state,
+        totalCount: totalCount,
+        volumeBucketMap: volumeBucketMap,
+        volumeOptions: volumeOptions,
+        lastUpdated: Number(moment())
+      });
+    }).catch(error => {
+      setLoading(false);
+      showDataFetchError(error.toString());
+    });
+  }
+
+  let autoReloadHelper: AutoReloadHelper = new AutoReloadHelper(loadData);
+
+  useEffect(() => {
+    autoReloadHelper.startPolling();
+    addAclColumn();
+    const initialVolume = getVolumeSearchParam();
+    if (initialVolume) {
+      setSelectedVolumes([{
+        label: initialVolume,
+        value: initialVolume
+      }]);
+    }
+    loadData();
+
+    return (() => {
+      autoReloadHelper.stopPolling();
+      cancelSignal && cancelSignal.abort();
+    })
+  }, []);
+
+  useEffect(() => {
+    // If the data is fetched, we need to regenerate the columns
+    // To make sure the filters are properly applied
+    setState({
+      ...state,
+      bucketsUnderVolume: getFilteredBuckets(
+        selectedVolumes,
+        state.volumeBucketMap
+      )
+    });
+  }, [state.volumeBucketMap])
+
+  // If limit changes, load new data
+  useEffect(() => {
+    loadData();
+  }, [selectedLimit.value]);
+
+  const {
+    lastUpdated, columnOptions,
+    volumeOptions, bucketsUnderVolume
+  } = state;
+
+  return (
+    <>
+      <div className='page-header-v2'>
+        Buckets
+        <AutoReloadPanel
+          isLoading={loading}
+          lastRefreshed={lastUpdated}
+          togglePolling={autoReloadHelper.handleAutoReloadToggle}
+          onReload={loadData}
+        />
+      </div>
+      <div style={{ padding: '24px' }}>
+        <div className='content-div'>
+          <div className='table-header-section'>
+            <div className='table-filter-section'>
+              <MultiSelect
+                options={volumeOptions}
+                defaultValue={selectedVolumes}
+                selected={selectedVolumes}
+                placeholder='Volumes'
+                onChange={handleVolumeChange}
+                fixedColumn=''
+                onTagClose={() => { }}
+                columnLength={volumeOptions.length} />
+              <MultiSelect
+                options={columnOptions}
+                defaultValue={selectedColumns}
+                selected={selectedColumns}
+                placeholder='Columns'
+                onChange={handleColumnChange}
+                onTagClose={() => { }}
+                fixedColumn='name'
+                columnLength={COLUMNS.length} />
+              <SingleSelect
+                options={LIMIT_OPTIONS}
+                defaultValue={selectedLimit}
+                placeholder='Limit'
+                onChange={handleLimitChange} />
+            </div>
+            <Search
+              disabled={bucketsUnderVolume?.length < 1}
+              searchOptions={SearchableColumnOpts}
+              searchInput={searchTerm}
+              searchColumn={searchColumn}
+              onSearchChange={
+                (e: React.ChangeEvent<HTMLInputElement>) => 
setSearchTerm(e.target.value)
+              }
+              onChange={(value) => {
+                setSearchTerm('');
+                setSearchColumn(value as 'name' | 'volumeName');
+              }} />
+          </div>
+          <div>
+            <Table
+              dataSource={getFilteredData(bucketsUnderVolume)}
+              columns={filterSelectedColumns()}
+              loading={loading}
+              rowKey='volume'
+              pagination={paginationConfig}
+              scroll={{ x: 'max-content', scrollToFirstRowOnChange: true }}
+              locale={{ filterTitle: '' }}
+            />
+          </div>
+        </div>
+        <AclPanel
+          visible={showPanel}
+          acls={currentRow.acls}
+          entityName={currentRow.name}
+          entityType='Bucket'
+          onClose={() => setShowPanel(false)} />
+      </div>
+    </>
+  )
+}
+
+export default Buckets;
\ No newline at end of file
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 6c323fc949..605883caff 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
@@ -195,7 +195,7 @@ const Volumes: React.FC<{}> = () => {
     request.then(response => {
       const volumesResponse: VolumesResponse = response.data;
       const volumes: Volume[] = volumesResponse.volumes;
-      const data: Volume[] = volumes.map(volume => {
+      const data: Volume[] = volumes?.map(volume => {
         return {
           volume: volume.volume,
           owner: volume.owner,
@@ -207,7 +207,7 @@ const Volumes: React.FC<{}> = () => {
           usedNamespace: volume.usedNamespace,
           acls: volume.acls
         };
-      });
+      }) ?? [];
 
       setState({
         ...state,
@@ -308,8 +308,7 @@ const Volumes: React.FC<{}> = () => {
                 placeholder='Columns'
                 onChange={handleColumnChange}
                 onTagClose={handleTagClose}
-                fixedColumn='Volume'
-                isOptionDisabled={(option) => option.value === 'volume'}
+                fixedColumn='volume'
                 columnLength={COLUMNS.length} />
               <SingleSelect
                 options={LIMIT_OPTIONS}
@@ -318,6 +317,7 @@ const Volumes: React.FC<{}> = () => {
                 onChange={handleLimitChange} />
             </div>
             <Search
+              disabled={data?.length < 1}
               searchOptions={SearchableColumnOpts}
               searchInput={searchTerm}
               searchColumn={searchColumn}
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/routes-v2.tsx
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/routes-v2.tsx
index 5d71024616..8a37ef9c51 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/routes-v2.tsx
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/routes-v2.tsx
@@ -19,6 +19,7 @@ import { lazy } from 'react';
 
 const Overview = lazy(() => import('@/v2/pages/overview/overview'));
 const Volumes = lazy(() => import('@/v2/pages/volumes/volumes'))
+const Buckets = lazy(() => import('@/v2/pages/buckets/buckets'));
 
 export const routesV2 = [
   {
@@ -28,5 +29,9 @@ export const routesV2 = [
   {
     path: '/Volumes',
     component: Volumes
+  },
+  {
+    path: '/Buckets',
+    component: Buckets
   }
 ];
diff --git 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/bucket.types.ts
 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/bucket.types.ts
index 8b2fd0c694..5cfc89d85e 100644
--- 
a/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/bucket.types.ts
+++ 
b/hadoop-ozone/recon/src/main/resources/webapps/recon/ozone-recon-web/src/v2/types/bucket.types.ts
@@ -17,6 +17,8 @@
  */
 
 import { Acl } from "@/v2/types/acl.types";
+import { Option } from "@/v2/components/select/singleSelect";
+import { Option as MultiOption } from "@/v2/components/select/multiSelect";
 
 // Corresponds to OzoneManagerProtocolProtos.StorageTypeProto
 export const BucketStorageTypeList = [
@@ -38,8 +40,8 @@ export type BucketLayout = typeof 
BucketLayoutTypeList[number];
 
 export type Bucket = {
   volumeName: string;
-  bucketName: string;
-  isVersionEnabled: boolean;
+  name: string;
+  versioning: boolean;
   storageType: BucketStorage;
   creationTime: number;
   modificationTime: number;
@@ -53,3 +55,17 @@ export type Bucket = {
   acls?: Acl[];
   bucketLayout: BucketLayout;
 }
+
+export type BucketResponse = {
+  totalCount: number;
+  buckets: Bucket[];
+}
+
+export type BucketsState = {
+  totalCount: number;
+  lastUpdated: number;
+  columnOptions: MultiOption[];
+  volumeBucketMap: Map<string, Set<Bucket>>;
+  bucketsUnderVolume: Bucket[];
+  volumeOptions: MultiOption[];
+}
\ No newline at end of file


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


Reply via email to