This is an automated email from the ASF dual-hosted git repository.
jialiang pushed a commit to branch frontend-refactor
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/frontend-refactor by this push:
new fc6bc4ba7b AMBARI-26173: common-components for ambari admin
implementation #3876
fc6bc4ba7b is described below
commit fc6bc4ba7b88fb581c5e199405eb6c2c81476a46
Author: vanshuhassija <[email protected]>
AuthorDate: Tue Nov 12 06:27:36 2024 +0530
AMBARI-26173: common-components for ambari admin implementation #3876
---
.../resources/ui/ambari-admin/package-lock.json | 457 +++++++++++++++++++--
.../main/resources/ui/ambari-admin/package.json | 2 +
.../src/components/ComboSearch/index.tsx | 223 ++++++++++
.../src/components/ConfirmationModal/index.tsx | 72 ++++
.../{Spinner.tsx => DefaultButton/index.tsx} | 13 +-
.../{Spinner.tsx => ErrorOverlay/index.tsx} | 26 +-
.../src/components/Paginator/index.tsx | 106 +++++
.../components/{Spinner.tsx => Spinner/index.tsx} | 0
.../ui/ambari-admin/src/components/Table/index.tsx | 158 +++++++
.../components/{Spinner.tsx => Table/style.css} | 28 +-
.../Spinner.tsx => hooks/usePagination.ts} | 33 +-
11 files changed, 1056 insertions(+), 62 deletions(-)
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/package-lock.json
b/ambari-admin/src/main/resources/ui/ambari-admin/package-lock.json
index c96905c28b..f560addcc1 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/package-lock.json
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/package-lock.json
@@ -10,6 +10,7 @@
"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
+ "@tanstack/react-table": "^8.20.5",
"@types/lodash": "^4.17.12",
"bootstrap": "^5.3.3",
"lodash": "^4.17.21",
@@ -19,6 +20,7 @@
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^5.3.4",
+ "react-select": "^5.8.3",
"sass": "^1.77.6"
},
"devDependencies": {
@@ -54,7 +56,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",
"integrity":
"sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/highlight": "^7.25.7",
@@ -109,7 +110,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz",
"integrity":
"sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.25.7",
@@ -142,7 +142,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz",
"integrity":
"sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.25.7",
@@ -199,7 +198,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz",
"integrity":
"sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -209,7 +207,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz",
"integrity":
"sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -243,7 +240,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz",
"integrity":
"sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.25.7",
@@ -259,7 +255,6 @@
"version": "7.25.8",
"resolved":
"https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz",
"integrity":
"sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.25.8"
@@ -319,7 +314,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz",
"integrity":
"sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.25.7",
@@ -334,7 +328,6 @@
"version": "7.25.7",
"resolved":
"https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz",
"integrity":
"sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.25.7",
@@ -353,7 +346,6 @@
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
"integrity":
"sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -363,7 +355,6 @@
"version": "7.25.8",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz",
"integrity":
"sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.25.7",
@@ -374,6 +365,138 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emotion/babel-plugin": {
+ "version": "11.12.0",
+ "resolved":
"https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz",
+ "integrity":
"sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.16.7",
+ "@babel/runtime": "^7.18.3",
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/serialize": "^1.2.0",
+ "babel-plugin-macros": "^3.1.0",
+ "convert-source-map": "^1.5.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-root": "^1.1.0",
+ "source-map": "^0.5.7",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved":
"https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity":
"sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved":
"https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity":
"sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@emotion/cache": {
+ "version": "11.13.1",
+ "resolved":
"https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz",
+ "integrity":
"sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/sheet": "^1.4.0",
+ "@emotion/utils": "^1.4.0",
+ "@emotion/weak-memoize": "^0.4.0",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
+ "integrity":
"sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.9.0",
+ "resolved":
"https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
+ "integrity":
"sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/react": {
+ "version": "11.13.3",
+ "resolved":
"https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz",
+ "integrity":
"sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.12.0",
+ "@emotion/cache": "^11.13.0",
+ "@emotion/serialize": "^1.3.1",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
+ "@emotion/utils": "^1.4.0",
+ "@emotion/weak-memoize": "^0.4.0",
+ "hoist-non-react-statics": "^3.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/serialize": {
+ "version": "1.3.2",
+ "resolved":
"https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz",
+ "integrity":
"sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/unitless": "^0.10.0",
+ "@emotion/utils": "^1.4.1",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@emotion/sheet": {
+ "version": "1.4.0",
+ "resolved":
"https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
+ "integrity":
"sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.10.0",
+ "resolved":
"https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
+ "integrity":
"sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
+ "version": "1.1.0",
+ "resolved":
"https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz",
+ "integrity":
"sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@emotion/utils": {
+ "version": "1.4.1",
+ "resolved":
"https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz",
+ "integrity":
"sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/weak-memoize": {
+ "version": "0.4.0",
+ "resolved":
"https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
+ "integrity":
"sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
+ "license": "MIT"
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved":
"https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -899,6 +1022,31 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.6.8",
+ "resolved":
"https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz",
+ "integrity":
"sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.8"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.6.12",
+ "resolved":
"https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz",
+ "integrity":
"sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.6.0",
+ "@floating-ui/utils": "^0.2.8"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.8",
+ "resolved":
"https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz",
+ "integrity":
"sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==",
+ "license": "MIT"
+ },
"node_modules/@fortawesome/fontawesome-common-types": {
"version": "6.6.0",
"resolved":
"https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz",
@@ -1002,7 +1150,6 @@
"version": "0.3.5",
"resolved":
"https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
"integrity":
"sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/set-array": "^1.2.1",
@@ -1017,7 +1164,6 @@
"version": "3.1.2",
"resolved":
"https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity":
"sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -1027,7 +1173,6 @@
"version": "1.2.1",
"resolved":
"https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
"integrity":
"sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
@@ -1037,14 +1182,12 @@
"version": "1.5.0",
"resolved":
"https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity":
"sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.25",
"resolved":
"https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
"integrity":
"sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -1389,6 +1532,39 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@tanstack/react-table": {
+ "version": "8.20.5",
+ "resolved":
"https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.20.5.tgz",
+ "integrity":
"sha512-WEHopKw3znbUZ61s9i0+i9g8drmDo6asTWbrQh8Us63DAk/M0FkmIqERew6P71HI75ksZ2Pxyuf4vvKh9rAkiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/table-core": "8.20.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
+ "node_modules/@tanstack/table-core": {
+ "version": "8.20.5",
+ "resolved":
"https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.20.5.tgz",
+ "integrity":
"sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved":
"https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1461,6 +1637,12 @@
"integrity":
"sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==",
"license": "MIT"
},
+ "node_modules/@types/parse-json": {
+ "version": "4.0.2",
+ "resolved":
"https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
+ "integrity":
"sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
+ "license": "MIT"
+ },
"node_modules/@types/prop-types": {
"version": "15.7.13",
"resolved":
"https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz",
@@ -1831,7 +2013,6 @@
"version": "3.2.1",
"resolved":
"https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity":
"sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-convert": "^1.9.0"
@@ -1860,6 +2041,21 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/babel-plugin-macros": {
+ "version": "3.1.0",
+ "resolved":
"https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
+ "integrity":
"sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "cosmiconfig": "^7.0.0",
+ "resolve": "^1.19.0"
+ },
+ "engines": {
+ "node": ">=10",
+ "npm": ">=6"
+ }
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved":
"https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1958,7 +2154,6 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity":
"sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -1989,7 +2184,6 @@
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity":
"sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^3.2.1",
@@ -2046,7 +2240,6 @@
"version": "1.9.3",
"resolved":
"https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity":
"sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"color-name": "1.1.3"
@@ -2056,7 +2249,6 @@
"version": "1.1.3",
"resolved":
"https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity":
"sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true,
"license": "MIT"
},
"node_modules/concat-map": {
@@ -2073,6 +2265,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cosmiconfig": {
+ "version": "7.1.0",
+ "resolved":
"https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+ "integrity":
"sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved":
"https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -2098,7 +2306,6 @@
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity":
"sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -2145,6 +2352,15 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity":
"sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
"node_modules/esbuild": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
@@ -2198,7 +2414,6 @@
"version": "1.0.5",
"resolved":
"https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity":
"sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.8.0"
@@ -2557,6 +2772,12 @@
"node": ">=8"
}
},
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity":
"sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "license": "MIT"
+ },
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -2609,6 +2830,15 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved":
"https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity":
"sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved":
"https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -2665,12 +2895,23 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity":
"sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity":
"sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/history": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
@@ -2714,7 +2955,6 @@
"version": "3.3.0",
"resolved":
"https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
"integrity":
"sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
@@ -2752,6 +2992,12 @@
"loose-envify": "^1.0.0"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved":
"https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity":
"sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT"
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved":
"https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -2764,6 +3010,21 @@
"node": ">=8"
}
},
+ "node_modules/is-core-module": {
+ "version": "2.15.1",
+ "resolved":
"https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
+ "integrity":
"sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved":
"https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2830,7 +3091,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
"integrity":
"sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
- "dev": true,
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
@@ -2846,6 +3106,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved":
"https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity":
"sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT"
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved":
"https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -2897,6 +3163,12 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved":
"https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity":
"sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
"node_modules/locate-path": {
"version": "6.0.0",
"resolved":
"https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -2948,6 +3220,12 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/memoize-one": {
+ "version": "6.0.0",
+ "resolved":
"https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+ "integrity":
"sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
+ "license": "MIT"
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -2989,7 +3267,6 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity":
"sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -3097,7 +3374,6 @@
"version": "1.0.1",
"resolved":
"https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity":
"sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
@@ -3106,6 +3382,24 @@
"node": ">=6"
}
},
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved":
"https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity":
"sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/path": {
"version": "0.12.7",
"resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
@@ -3136,6 +3430,12 @@
"node": ">=8"
}
},
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved":
"https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity":
"sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "license": "MIT"
+ },
"node_modules/path-to-regexp": {
"version": "1.9.0",
"resolved":
"https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz",
@@ -3145,11 +3445,19 @@
"isarray": "0.0.1"
}
},
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity":
"sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved":
"https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity":
"sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
- "dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
@@ -3398,6 +3706,27 @@
"react": ">=15"
}
},
+ "node_modules/react-select": {
+ "version": "5.8.3",
+ "resolved":
"https://registry.npmjs.org/react-select/-/react-select-5.8.3.tgz",
+ "integrity":
"sha512-lVswnIq8/iTj1db7XCG74M/3fbGB6ZaluCzvwPGT5ZOjCdL/k0CLWhEK0vCBLuU5bHTEf6Gj8jtSvi+3v+tO1w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.0",
+ "@emotion/cache": "^11.4.0",
+ "@emotion/react": "^11.8.1",
+ "@floating-ui/dom": "^1.0.1",
+ "@types/react-transition-group": "^4.4.0",
+ "memoize-one": "^6.0.0",
+ "prop-types": "^15.6.0",
+ "react-transition-group": "^4.3.0",
+ "use-isomorphic-layout-effect": "^1.1.2"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved":
"https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -3432,11 +3761,27 @@
"integrity":
"sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"license": "MIT"
},
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity":
"sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved":
"https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity":
"sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -3578,6 +3923,15 @@
"node": ">=8"
}
},
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved":
"https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity":
"sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved":
"https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -3600,11 +3954,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
+ "integrity":
"sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
+ "license": "MIT"
+ },
"node_modules/supports-color": {
"version": "5.5.0",
"resolved":
"https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity":
"sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^3.0.0"
@@ -3613,6 +3972,18 @@
"node": ">=4"
}
},
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved":
"https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity":
"sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/text-table": {
"version": "0.2.0",
"resolved":
"https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -3636,7 +4007,6 @@
"version": "2.0.0",
"resolved":
"https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity":
"sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
@@ -3780,6 +4150,20 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-isomorphic-layout-effect": {
+ "version": "1.1.2",
+ "resolved":
"https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
+ "integrity":
"sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/util": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
@@ -3897,6 +4281,15 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity":
"sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved":
"https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/ambari-admin/src/main/resources/ui/ambari-admin/package.json
b/ambari-admin/src/main/resources/ui/ambari-admin/package.json
index a963bb51b4..3b406b6ba1 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/package.json
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/package.json
@@ -12,6 +12,7 @@
"dependencies": {
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
+ "@tanstack/react-table": "^8.20.5",
"@types/lodash": "^4.17.12",
"bootstrap": "^5.3.3",
"lodash": "^4.17.21",
@@ -21,6 +22,7 @@
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^5.3.4",
+ "react-select": "^5.8.3",
"sass": "^1.77.6"
},
"devDependencies": {
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ComboSearch/index.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ComboSearch/index.tsx
new file mode 100644
index 0000000000..83bd75292e
--- /dev/null
+++
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ComboSearch/index.tsx
@@ -0,0 +1,223 @@
+/**
+ * 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.
+ */
+/* eslint-disable @typescript-eslint/ban-types */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { useEffect, useState } from "react";
+import Select, { SingleValue } from "react-select";
+import { get } from "lodash";
+import { Badge, Button } from "react-bootstrap";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faClose } from "@fortawesome/free-solid-svg-icons";
+type FilterField = { label: string; value: string };
+type PropTypes = {
+ fields: FilterField[];
+ data: any;
+ valueMappings?: { [key: string]: string };
+ searchCallback: Function;
+};
+function ComboSearch({ fields, data, searchCallback }: PropTypes) {
+ const [selectedFilters, setSelectedFilters] = useState<
+ { field: FilterField; value: FilterField }[]
+ >([]);
+ const [selectedField, setSelectedField] = useState<FilterField>(
+ {} as FilterField
+ );
+ const [selectedValue, setSelectedValue] = useState<FilterField>(
+ {} as FilterField
+ );
+ const [valueOptions, setValueOptions] = useState<FilterField[]>([]);
+ function getCorrespondingValues(){
+ const mappedKey = selectedField.value;
+ let allValues: any[] = [];
+ data.forEach((item: any) => {
+ const value = get(item, mappedKey, "");
+ if (!value) {
+ // Ignore empty value
+ return;
+ }
+ if (Array.isArray(value)) {
+ allValues = [...allValues, ...value];
+ } else if (typeof value !== "object") {
+ allValues.push(value);
+ }
+ });
+ const uniqueValues = [...new Set(allValues)];
+ console.log("Unique values", uniqueValues);
+ const correspondingValues = uniqueValues.filter(item=>{
+ return
selectedValue?.value!==item&&!!!selectedFilters?.find(fil=>fil.value.value===item)
+ }).map((item: any) => {
+ return {
+ label: item,
+ value: item,
+ };
+ });
+ return correspondingValues;
+ }
+ // START GENAI@CHATGPT4
+ useEffect(() => {
+ if (selectedField) {
+ const correspondingValues = getCorrespondingValues();
+ setSelectedValue({} as FilterField);
+ setValueOptions(correspondingValues);
+ }
+ }, [selectedField]);
+
+ useEffect(()=>{
+ if(selectedValue){
+ const correspondingValues=getCorrespondingValues();
+ setValueOptions(correspondingValues);
+ }
+ },[selectedValue,selectedFilters])
+
+ const filterData = (data: any) => {
+ const categoryFilters: { [key: string]: any } = {};
+
+ selectedFilters.forEach((filter) => {
+ const category = filter.field.value;
+ if (!categoryFilters[category]) {
+ categoryFilters[category] = [];
+ }
+ categoryFilters[category].push(filter.value.value);
+ });
+
+ const filteredData = data.filter((item: any) => {
+ return Object.keys(categoryFilters).every((category) => {
+ // Apply OR logic within the same category
+ const itemValue = get(item, category);
+ return Array.isArray(itemValue)
+ ? itemValue.some((v) => categoryFilters[category].includes(v))
+ : categoryFilters[category].includes(itemValue);
+ });
+ });
+ return filteredData;
+ };
+ useEffect(() => {
+ if (selectedFilters.length) {
+ searchCallback(filterData(data));
+ } else {
+ searchCallback(data);
+ }
+ console.log("Selected Filters", selectedFilters);
+ }, [selectedFilters.length]);
+ function addFilter(e: any) {
+ e.preventDefault();
+ const newFilter = { field: selectedField, value: selectedValue };
+ if (
+ !selectedFilters.some(
+ (filter) =>
+ filter.field.value === newFilter.field.value &&
+ filter.value.value === newFilter.value.value
+ )
+ ) {
+ setSelectedFilters([...selectedFilters, newFilter]);
+ setSelectedField(null as any);
+ setSelectedValue(null as any)
+ }
+ }
+ function deleteFilter(filterToDelete: {
+ field: { label: string; value: any };
+ value: { label: string; value: any };
+ }) {
+ setSelectedFilters((prevFilters) => {
+ return prevFilters.filter((filter) => {
+ return !(
+ filter.field.value === filterToDelete.field.value &&
+ filter.value.value === filterToDelete.value.value
+ );
+ });
+ });
+ }
+ function resetFilters() {
+ setSelectedField(null as any);
+ setSelectedValue(null as any);
+ setSelectedFilters([]);
+ }
+ return (
+ <div className="d-flex w-100 flex-column ease show"
data-testid="search-filters">
+ <div className="text-muted">
+ Select filter(s) to tailor your search. Records update immediately to
+ reflect your preferences.
+ </div>
+ <div className="d-flex mt-2">
+ <form onSubmit={addFilter} className="d-flex w-100 align-items-center">
+ <Select
+ value={selectedField}
+ menuPortalTarget={document.body}
+ options={fields}
+ placeholder="Select field"
+ className="w-25"
+ onChange={(value:SingleValue<FilterField>) => {
+ setSelectedField(value as FilterField);
+ }}
+ ></Select>
+ <Select
+ className="ms-2 w-25"
+ menuPortalTarget={document.body}
+ value={selectedValue}
+ options={valueOptions}
+ placeholder="Value"
+ onChange={(value) => {
+ setSelectedValue(value as FilterField);
+ }}
+ ></Select>
+ <Button
+ disabled={!selectedField?.label || !selectedValue?.value}
+ size="sm"
+ variant="outline-secondary"
+ onClick={addFilter}
+ type="submit"
+ className="ms-2"
+ >
+ Add Filter
+ </Button>
+ <Button
+ size="sm"
+ variant="outline-danger"
+ onClick={resetFilters}
+ className="ms-2"
+ >
+ Reset Filters
+ </Button>
+ </form>
+ </div>
+ <div className="mt-2 d-flex flex-wrap">
+ {selectedFilters.map((fil, index) => {
+ return (
+ <Badge
+ bg={`secondary d-flex mt-2 align-items-center text-white ${
+ index > 0 ? "ms-2" : ""
+ }`}
+ >
+ <div className="text-white">{fil.field.label}:</div>
+ <div className="ms-2 text-white">{fil.value.label}</div>
+ <FontAwesomeIcon
+ icon={faClose}
+ onClick={() => {
+ deleteFilter(fil);
+ }}
+ className="delete-filter cursot-pointer ms-2"
+ />
+ </Badge>
+ );
+ })}
+ </div>
+ </div>
+ );
+}
+
+export default ComboSearch;
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ConfirmationModal/index.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ConfirmationModal/index.tsx
new file mode 100644
index 0000000000..9fab2da1d1
--- /dev/null
+++
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ConfirmationModal/index.tsx
@@ -0,0 +1,72 @@
+/**
+ * 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 { Button, Modal } from "react-bootstrap";
+import DefaultButton from "../DefaultButton";
+
+type ConfirmationModalProps = {
+ isOpen: boolean;
+ onClose: () => void;
+ modalTitle: string;
+ modalBody: string;
+ successCallback: () => void;
+ buttonVariant?: string;
+};
+
+export default function ConfirmationModal({
+ isOpen,
+ onClose,
+ modalTitle,
+ modalBody,
+ successCallback,
+ buttonVariant = "success",
+}: ConfirmationModalProps) {
+ return (
+ <Modal
+ show={isOpen}
+ onHide={onClose}
+ size="lg"
+ className="custom-modal-container modal-width"
+ data-testid="confirmation-modal"
+ >
+ <Modal.Header>
+ <Modal.Title>
+ <h3>{modalTitle}</h3>
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>{modalBody}</Modal.Body>
+ <Modal.Footer className="d-flex justify-content-end">
+ <DefaultButton
+ size="sm"
+ onClick={onClose}
+ data-testid="confirm-cancel-btn"
+ >
+ CANCEL
+ </DefaultButton>
+ <Button
+ className="custom-btn"
+ variant={buttonVariant}
+ onClick={successCallback}
+ size="sm"
+ data-testid="confirm-ok-btn"
+ >
+ OK
+ </Button>
+ </Modal.Footer>
+ </Modal>
+ );
+}
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/DefaultButton/index.tsx
similarity index 75%
copy from
ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
copy to
ambari-admin/src/main/resources/ui/ambari-admin/src/components/DefaultButton/index.tsx
index c4a47c2ea2..9bc09cfa86 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
+++
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/DefaultButton/index.tsx
@@ -15,12 +15,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Spinner as DefaultSpinner } from "react-bootstrap";
+import { Button } from "react-bootstrap";
-export default function Spinner() {
- return (
- <div className="d-flex justify-content-center align-items-center m-5"
data-testid="admin-spinner">
- <DefaultSpinner />
- </div>
- );
+function DefaultButton({ className, ...props }: any) {
+ className = className ? className + " btn-default" : "btn-default";
+ return <Button className={className} {...props}></Button>;
}
+
+export default DefaultButton;
\ No newline at end of file
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ErrorOverlay/index.tsx
similarity index 63%
copy from
ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
copy to
ambari-admin/src/main/resources/ui/ambari-admin/src/components/ErrorOverlay/index.tsx
index c4a47c2ea2..cd39597484 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
+++
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/ErrorOverlay/index.tsx
@@ -15,12 +15,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Spinner as DefaultSpinner } from "react-bootstrap";
+import { Overlay, Tooltip } from "react-bootstrap";
-export default function Spinner() {
- return (
- <div className="d-flex justify-content-center align-items-center m-5"
data-testid="admin-spinner">
- <DefaultSpinner />
- </div>
- );
+type ErrorOverlayProps = {
+ target: React.RefObject<HTMLElement>;
+ showTooltip: boolean;
+ errorMessage: string;
}
+
+export default function ErrorOverlay({target, showTooltip, errorMessage}:
ErrorOverlayProps) {
+ return <Overlay
+ target={target.current}
+ show={showTooltip}
+ placement="top"
+ >
+ {(props) => (
+ <Tooltip {...props}>
+ {errorMessage}
+ </Tooltip>
+ )}
+ </Overlay>
+}
\ No newline at end of file
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Paginator/index.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Paginator/index.tsx
new file mode 100644
index 0000000000..b38ba54c1d
--- /dev/null
+++
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Paginator/index.tsx
@@ -0,0 +1,106 @@
+/**
+ * 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 { Dropdown, DropdownButton, Pagination } from "react-bootstrap";
+
+type PaginatorProps = {
+ currentPage: number;
+ maxPage: number;
+ changePage: (pageNumber: number) => void;
+ itemsPerPage: number;
+ setItemsPerPage: (recordsCount: number) => void;
+ totalItems: number;
+};
+
+const Paginator = ({
+ currentPage,
+ maxPage,
+ changePage,
+ itemsPerPage,
+ setItemsPerPage,
+ totalItems,
+}: PaginatorProps) => {
+ const items = [];
+ const perPageOptions = [10, 25, 50, 100];
+ for (let number = 1; number <= maxPage; number++) {
+ if (
+ number === currentPage - 1 ||
+ number === currentPage ||
+ number === currentPage + 1 ||
+ number === 1 ||
+ number === maxPage
+ ) {
+ items.push(
+ <Pagination.Item
+ key={number}
+ active={number === currentPage}
+ onClick={() => changePage(number)}
+ className="pagination-btn"
+ >
+ {number}
+ </Pagination.Item>
+ );
+ } else if (number === currentPage - 2 || number === currentPage + 2) {
+ items.push(<Pagination.Ellipsis />);
+ }
+ }
+ const firstItemIndex = (currentPage - 1) * itemsPerPage + 1;
+ const lastItemIndex = Math.min(currentPage * itemsPerPage, totalItems);
+ return (
+ <>
+ {totalItems > 10 ? (
+ <div className="mt-4 border p-3 py-0" data-testid="pagination">
+ <div className="d-flex justify-content-between align-items-center
py-0">
+ <div>
+ Showing {firstItemIndex}-{lastItemIndex} of {totalItems} items
+ </div>
+ <div className="mt-3 d-flex">
+ <DropdownButton title={itemsPerPage} size="sm" variant="light">
+ {perPageOptions.map((perPageOption) => {
+ return (
+ <Dropdown.Item
+ key={perPageOption}
+ onClick={() => {
+ setItemsPerPage(perPageOption);
+ }}
+ >
+ {perPageOption}
+ </Dropdown.Item>
+ );
+ })}
+ </DropdownButton>
+ <Pagination>
+ <Pagination.Prev
+ title="Previous"
+ className="ms-1"
+ onClick={() => changePage(currentPage - 1)}
+ />
+ {items}
+ <Pagination.Next
+ className="ms-1"
+ onClick={() => changePage(currentPage + 1)}
+ />
+ </Pagination>
+ </div>
+ </div>
+ </div>
+ ) : null}
+ </>
+ );
+};
+
+export default Paginator;
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner/index.tsx
similarity index 100%
copy from
ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
copy to
ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner/index.tsx
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Table/index.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Table/index.tsx
new file mode 100644
index 0000000000..6b8bb09dc8
--- /dev/null
+++
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Table/index.tsx
@@ -0,0 +1,158 @@
+/**
+ * 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.
+ */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import React from "react";
+import {
+ ColumnDef,
+ flexRender,
+ getCoreRowModel,
+ getSortedRowModel,
+ OnChangeFn,
+ SortingState,
+ useReactTable,
+} from "@tanstack/react-table";
+import { Table as BootstrapTable } from "react-bootstrap";
+import "./style.css";
+import { get } from "lodash";
+interface TableProps {
+ columns: ColumnDef<unknown, unknown>[];
+ data: unknown[];
+ onSortingChange?: OnChangeFn<SortingState>;
+ sorting?: SortingState;
+ className?: string;
+ restProps?: any;
+ striped?: boolean;
+ bordered?: boolean;
+ hover?: boolean;
+ entityName?: string;
+}
+
+const Table: React.FC<TableProps> = ({
+ columns,
+ data,
+ sorting,
+ onSortingChange,
+ entityName,
+ ...restProps
+}) => {
+ const table = useReactTable({
+ columns,
+ data,
+ debugTable: true,
+ getCoreRowModel: getCoreRowModel(),
+ getSortedRowModel: getSortedRowModel(), //client-side sorting
+ onSortingChange,
+ state: {
+ sorting,
+ },
+ });
+
+ if (!data.length && entityName) {
+ return (
+ <div className="d-flex justify-content-center">
+ <h4>NO {entityName.toUpperCase()} TO DISPLAY.</h4>
+ </div>
+ );
+ }
+
+ return (
+ <div>
+ <BootstrapTable responsive {...restProps}>
+ <thead>
+ {table.getHeaderGroups().map((headerGroup) => (
+ <tr key={headerGroup.id}>
+ {headerGroup.headers.map((header) => {
+ return (
+ <th key={header.id} colSpan={header.colSpan}>
+ {header.isPlaceholder ? null : (
+ <div
+ className={
+ header.column.getCanSort()
+ ? "cursor-pointer select-none"
+ : ""
+ }
+ onClick={() => {
+ if (!header.column.getCanSort()) return;
+ onSortingChange?.([
+ {
+ id: header.id,
+ desc:
+ sorting?.[0].id === header.id
+ ? !sorting[0].desc
+ : false,
+ },
+ ]);
+ header.column.getToggleSortingHandler();
+ }}
+ title={
+ header.column.getCanSort()
+ ? header.column.getNextSortingOrder() === "asc"
+ ? "Sort ascending"
+ : header.column.getNextSortingOrder() === "desc"
+ ? "Sort descending"
+ : "Clear sort"
+ : undefined
+ }
+ >
+ {flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+ {{
+ asc: "a",
+ desc: "d",
+ }[header.column.getIsSorted() as string] ?? null}
+ </div>
+ )}
+ </th>
+ );
+ })}
+ </tr>
+ ))}
+ </thead>
+ <tbody>
+ {table.getRowModel().rows.map((row) => {
+ return (
+ <tr key={row.id} className="text-break" role="listitem">
+ {row.getVisibleCells().map((cell) => {
+ return (
+ <td
+ key={cell.id}
+ style={{
+ width: get(cell, "column.columnDef.width", "auto")
+ }}
+ >
+ <div>
+ {flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext()
+ )}
+ </div>
+ </td>
+ );
+ })}
+ </tr>
+ );
+ })}
+ </tbody>
+ </BootstrapTable>
+ </div>
+ );
+};
+
+export default Table;
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Table/style.css
similarity index 67%
copy from
ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
copy to
ambari-admin/src/main/resources/ui/ambari-admin/src/components/Table/style.css
index c4a47c2ea2..eaaed4f923 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
+++
b/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Table/style.css
@@ -15,12 +15,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Spinner as DefaultSpinner } from "react-bootstrap";
-
-export default function Spinner() {
- return (
- <div className="d-flex justify-content-center align-items-center m-5"
data-testid="admin-spinner">
- <DefaultSpinner />
- </div>
- );
-}
+ .table thead,
+ .table thead th {
+ color: #999 !important;
+ font-weight: 700 !important;
+ }
+ .table tbody td {
+ color: #666 !important;
+ }
+ .table tbody td:hover {
+ cursor: default;
+ }
+ .table > thead > tr > th,
+ .table > tbody > tr > th,
+ .table > tfoot > tr > th,
+ .table > thead > tr > td,
+ .table > tbody > tr > td,
+ .table > tfoot > tr > td {
+ padding: 12px!important;
+ }
\ No newline at end of file
diff --git
a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
b/ambari-admin/src/main/resources/ui/ambari-admin/src/hooks/usePagination.ts
similarity index 54%
rename from
ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
rename to
ambari-admin/src/main/resources/ui/ambari-admin/src/hooks/usePagination.ts
index c4a47c2ea2..794e0f389d 100644
--- a/ambari-admin/src/main/resources/ui/ambari-admin/src/components/Spinner.tsx
+++ b/ambari-admin/src/main/resources/ui/ambari-admin/src/hooks/usePagination.ts
@@ -15,12 +15,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Spinner as DefaultSpinner } from "react-bootstrap";
+import { useState } from 'react';
-export default function Spinner() {
- return (
- <div className="d-flex justify-content-center align-items-center m-5"
data-testid="admin-spinner">
- <DefaultSpinner />
- </div>
+const usePagination = (items:any, initialItemsPerPage=10) => {
+ const [currentPage, setCurrentPage] = useState(1);
+ const [itemsPerPage, setItemsPerPage] = useState(initialItemsPerPage);
+
+ const maxPage = Math.ceil(items.length / itemsPerPage);
+
+ const currentItems = items.slice(
+ (currentPage - 1) * itemsPerPage,
+ currentPage * itemsPerPage
);
-}
+
+ const changePage = (newPage:number) => {
+ const safePage = Math.max(1, Math.min(newPage, maxPage));
+ setCurrentPage(safePage);
+ };
+
+ return {
+ currentItems,
+ changePage,
+ currentPage,
+ maxPage,
+ itemsPerPage,
+ setItemsPerPage
+ };
+};
+export default usePagination;
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]