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 ebbc4e2219da..3c472d5f7903 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(react-dom@16.14.0)(react@16.14.0) @@ -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/generator@7.25.5: - resolution: {integrity: sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==} + /@babel/generator@7.25.6: + 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/parser@7.25.4: - resolution: {integrity: sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==} + /@babel/parser@7.25.6: + 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/runtime@7.25.4: - resolution: {integrity: sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==} + /@babel/runtime@7.25.6: + 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/traverse@7.25.4: - resolution: {integrity: sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==} + /@babel/traverse@7.25.6: + 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/types@7.25.4: - resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==} + /@babel/types@7.25.6: + 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(react-dom@16.14.0)(react@16.14.0) '@ant-design/react-slick': 0.28.4(react@16.14.0) - '@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: /babel-plugin-macros@2.8.0: 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 /dayjs@1.11.13: @@ -2547,7 +2547,7 @@ packages: /dom-helpers@5.2.1: 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: /history@4.10.1: 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(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) rc-textarea: 0.3.7(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-motion: 2.9.2(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react@16.14.0) @@ -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(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) rc-overflow: 1.3.2(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-menu: 8.10.8(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) react: 16.14.0 react-dom: 16.14.0(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-tree: 4.1.5(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) rc-motion: 2.9.2(react-dom@16.14.0)(react@16.14.0) @@ -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(react-dom@16.14.0)(react@16.14.0) 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(react@16.14.0) 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(react-dom@16.14.0)(react@16.14.0) rc-util: 5.43.0(react-dom@16.14.0)(react@16.14.0) @@ -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(react@16.14.0) '@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 21d4341787ed..8cac2a9c0477 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 = ({ + disabled = false, searchColumn, searchInput = '', searchOptions = [], @@ -48,6 +50,7 @@ const Search: React.FC = ({ const selectFilter = searchColumn ? ( { } // ------------- Component -------------- // + +const Option: React.FC> = (props) => { + return ( +
+ + null} /> + + +
+ ) +} + + const MultiSelect: React.FC = ({ options = [], selected = [], @@ -58,24 +80,20 @@ const MultiSelect: React.FC = ({ ...props }) => { - const Option: React.FC> = (props) => { + const ValueContainer = ({ children, ...props }: ValueContainerProps) => { return ( -
- - null} /> - - -
- ) - } + + {React.Children.map(children, (child) => ( + ((child as React.ReactElement> + | React.ReactPortal)?.type as React.JSXElementConstructor)).name === "DummyInput" + ? child + : null + )} + {placeholder}: {selected.length} selected + + ); + }; return ( = ({ classNamePrefix='multi-select' options={options} components={{ + ValueContainer, Option }} placeholder={placeholder} value={selected} + isOptionDisabled={(option) => option.value === fixedColumn} onChange={(selected: ValueType) => { 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 41ab03f5982c..1d02b407334b 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 = ({ const ValueContainer = ({ children, ...props }: ValueContainerProps) => { - const selectedLimit = props.getValue() as Option[]; + const selectedValue = props.getValue() as Option[]; return ( {React.Children.map(children, (child) => ( @@ -60,7 +60,7 @@ const SingleSelect: React.FC = ({ ? child : null )} - Limit: {selectedLimit[0]?.label ?? ''} + {placeholder}: {selectedValue[0]?.label ?? ''} ); }; 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 000000000000..8f4c8ffaf9f2 --- /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 000000000000..bd8950e54c87 --- /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 + ? + : +}; + +const renderStorageType = (bucketStorage: BucketStorage) => { + const bucketStorageIconMap: Record = { + RAM_DISK: , + SSD: , + DISK: , + ARCHIVE: + }; + const icon = bucketStorage in bucketStorageIconMap + ? bucketStorageIconMap[bucketStorage] + : ; + return {icon} {bucketStorage}; +}; + +const renderBucketLayout = (bucketLayout: BucketLayout) => { + const bucketLayoutColorMap = { + FILE_SYSTEM_OPTIMIZED: 'green', + OBJECT_STORE: 'orange', + LEGACY: 'blue' + }; + const color = bucketLayout in bucketLayoutColorMap ? + bucketLayoutColorMap[bucketLayout] : ''; + return {bucketLayout}; +}; + +const SearchableColumnOpts = [{ + label: 'Bucket', + value: 'name' +}, { + label: 'Volume', + value: 'volumeName' +}] + +const COLUMNS: ColumnsType = [ + { + 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) => ( + + ) + }, + { + title: 'Namespace Capacity', + key: 'namespaceCapacity', + sorter: (a: Bucket, b: Bucket) => a.usedNamespace - b.usedNamespace, + render: (text: string, record: Bucket) => ( + + ) + }, + { + 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>, + 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().add(currentBucket)); + } + return map; + }, new Map>()); + return volumeBucketMap; +} + +function getFilteredBuckets( + selectedVolumes: Option[], + bucketsMap: Map> +) { + 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({ + totalCount: 0, + lastUpdated: 0, + columnOptions: defaultColumns, + volumeBucketMap: new Map>(), + bucketsUnderVolume: [], + volumeOptions: [], + }); + const [loading, setLoading] = useState(false); + const [selectedColumns, setSelectedColumns] = useState(defaultColumns); + const [selectedVolumes, setSelectedVolumes] = useState([]); + const [selectedLimit, setSelectedLimit] = useState