diff --git a/src/fireedge/package-lock.json b/src/fireedge/package-lock.json index 3d35b69f30..916f89acbb 100644 --- a/src/fireedge/package-lock.json +++ b/src/fireedge/package-lock.json @@ -20,7 +20,6 @@ "@babel/preset-react": "7.16.0", "@emotion/react": "11.6.0", "@emotion/styled": "11.6.0", - "@hookform/devtools": "4.0.1", "@hookform/resolvers": "2.8.2", "@loadable/babel-plugin": "5.13.2", "@loadable/component": "5.15.0", @@ -155,20 +154,20 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", - "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "dependencies": { - "@babel/highlight": "^7.16.0" + "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", - "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", "engines": { "node": ">=6.9.0" } @@ -221,11 +220,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", - "integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", + "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", "dependencies": { - "@babel/types": "^7.16.0", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -234,35 +233,35 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz", - "integrity": "sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.5.tgz", - "integrity": "sha512-3JEA9G5dmmnIWdzaT9d0NmFRgYnWUThLsDaL7982H0XqqWr56lRrsmwheXFMjR+TMl7QMBb6mzy9kvgr1lRLUA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz", - "integrity": "sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "dependencies": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-validator-option": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", "browserslist": "^4.17.5", "semver": "^6.3.0" }, @@ -274,17 +273,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz", - "integrity": "sha512-NEohnYA7mkB8L5JhU7BLwcBdU3j83IziR9aseMueWGeAjblbul3zzb8UvJ3a1zuBiqCMObzCJHFqKIQE6hTVmg==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", + "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-member-expression-to-functions": "^7.16.5", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.5", - "@babel/helper-split-export-declaration": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -294,12 +293,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz", - "integrity": "sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" }, "engines": { "node": ">=6.9.0" @@ -327,155 +326,155 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz", - "integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz", - "integrity": "sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", - "integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "dependencies": { - "@babel/helper-get-function-arity": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz", - "integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz", - "integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz", - "integrity": "sha512-7fecSXq7ZrLE+TWshbGT+HyCLkxloWNhTbU2QM1NTI/tDqyf0oZiMcEfYtDuUDCo528EOlt39G1rftea4bRZIw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", - "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz", - "integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-simple-access": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz", - "integrity": "sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", - "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz", - "integrity": "sha512-X+aAJldyxrOmN9v3FKp+Hu1NO69VWgYgDGq6YDykwRPzxs5f2N+X988CBXS7EQahDU+Vpet5QYMqLk+nsp+Qxw==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-wrap-function": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.5.tgz", - "integrity": "sha512-ao3seGVa/FZCMCCNDuBcqnBFSbdr8N2EW35mzojx3TwfIbdPmNK+JV6+2d5bR0Z71W5ocLnQp9en/cTF7pBJiQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "dependencies": { - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-member-expression-to-functions": "^7.16.5", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz", - "integrity": "sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -493,65 +492,65 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz", - "integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "dependencies": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz", - "integrity": "sha512-2J2pmLBqUqVdJw78U0KPNdeE2qeuIyKoG4mKV7wAq3mc4jJG282UgjZw4ZYDnqiWQuS3Y3IYdF/AQ6CpyBV3VA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "dependencies": { - "@babel/helper-function-name": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", - "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.0.tgz", + "integrity": "sha512-Xe/9NFxjPwELUvW2dsukcMZIp6XwPSbI4ojFBJuX5ramHuVE22SVcZIwqzdWo5uCgeTXW8qV97lMvSOjq+1+nQ==", "dependencies": { - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -582,9 +581,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.16.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", - "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", + "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -593,13 +592,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz", - "integrity": "sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0" + "@babel/plugin-proposal-optional-chaining": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -609,11 +608,11 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.5.tgz", - "integrity": "sha512-kzdHgnaXRonttiTfKYnSVafbWngPPr2qKw9BWYBESl91W54e+9R5pP70LtWxV56g0f05f/SQrwHYkfvbwcdQ/A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, @@ -625,12 +624,12 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.5.tgz", - "integrity": "sha512-C/FX+3HNLV6sz7AqbTQqEo1L9/kfrKjxcVtgyBCmvIgOjvuBVUWooDoi7trsLxOzCEo5FccjRvKHkfDsJFZlfA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", + "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-remap-async-to-generator": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { @@ -656,12 +655,12 @@ } }, "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.5.tgz", - "integrity": "sha512-EEFzuLZcm/rNJ8Q5krK+FRKdVkd6FjfzT9tuSZql9sQn64K0hHA2KLJ0DqVot9/iV6+SsuadC5yI39zWnm+nmQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", + "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { @@ -672,11 +671,11 @@ } }, "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.5.tgz", - "integrity": "sha512-P05/SJZTTvHz79LNYTF8ff5xXge0kk5sIIWAypcWgX4BTRUgyHc8wRxJ/Hk+mU0KXldgOOslKaeqnhthcDJCJQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { @@ -687,11 +686,11 @@ } }, "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.5.tgz", - "integrity": "sha512-i+sltzEShH1vsVydvNaTRsgvq2vZsfyrd7K7vPLUU/KgS0D5yZMe6uipM0+izminnkKrEfdUnz7CxMRb6oHZWw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { @@ -702,11 +701,11 @@ } }, "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.5.tgz", - "integrity": "sha512-QQJueTFa0y9E4qHANqIvMsuxM/qcLQmKttBACtPCQzGUEizsXDACGonlPiSwynHfOa3vNw0FPMVvQzbuXwh4SQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { @@ -717,11 +716,11 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.5.tgz", - "integrity": "sha512-xqibl7ISO2vjuQM+MzR3rkd0zfNWltk7n9QhaD8ghMmMceVguYrNDt7MikRyj4J4v3QehpnrU8RYLnC7z/gZLA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -747,11 +746,11 @@ } }, "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.5.tgz", - "integrity": "sha512-DvB9l/TcsCRvsIV9v4jxR/jVP45cslTVC0PMVHvaJhhNuhn2Y1SOhCSFlPK777qLB5wb8rVDaNoqMTyOqtY5Iw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" }, "engines": { @@ -780,11 +779,11 @@ } }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.5.tgz", - "integrity": "sha512-ihCMxY1Iljmx4bWy/PIMJGXN4NS4oUj1MKynwO07kiKms23pNvIn1DMB92DNB2R0EA882sw0VXIelYGdtF7xEQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" }, "engines": { @@ -811,12 +810,12 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.5.tgz", - "integrity": "sha512-+yFMO4BGT3sgzXo+lrq7orX5mAZt57DwUK6seqII6AcJnJOIhBJ8pzKH47/ql/d426uQ7YhN8DpUFirQzqYSUA==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -826,13 +825,13 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.5.tgz", - "integrity": "sha512-+YGh5Wbw0NH3y/E5YMu6ci5qTDmAEVNoZ3I54aB6nVEOZ5BQ7QJlwKq5pYVucQilMByGn/bvX0af+uNaPRCabA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-create-class-features-plugin": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { @@ -843,12 +842,12 @@ } }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.5.tgz", - "integrity": "sha512-s5sKtlKQyFSatt781HQwv1hoM5BQ9qRH30r+dK56OLDsHmV74mzwJNX7R1yMuE7VZKG5O6q/gmOGSAO6ikTudg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=4" @@ -927,11 +926,11 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz", - "integrity": "sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", + "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1035,11 +1034,11 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.5.tgz", - "integrity": "sha512-8bTHiiZyMOyfZFULjsCnYOWG059FVMes0iljEHSfARhNgFfpsqE92OrCffv3veSw9rwMkYcFe9bj0ZoXU2IGtQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1049,13 +1048,13 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.5.tgz", - "integrity": "sha512-TMXgfioJnkXU+XRoj7P2ED7rUm5jbnDWwlCuFVTpQboMfbSya5WrmubNBAMlk7KXvywpo8rd8WuYZkis1o2H8w==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", "dependencies": { - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-remap-async-to-generator": "^7.16.5" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" }, "engines": { "node": ">=6.9.0" @@ -1065,11 +1064,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.5.tgz", - "integrity": "sha512-BxmIyKLjUGksJ99+hJyL/HIxLIGnLKtw772zYDER7UuycDZ+Xvzs98ZQw6NGgM2ss4/hlFAaGiZmMNKvValEjw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1079,11 +1078,11 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.5.tgz", - "integrity": "sha512-JxjSPNZSiOtmxjX7PBRBeRJTUKTyJ607YUYeT0QJCNdsedOe+/rXITjP08eG8xUpsLfPirgzdCFN+h0w6RI+pQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1093,17 +1092,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.5.tgz", - "integrity": "sha512-DzJ1vYf/7TaCYy57J3SJ9rV+JEuvmlnvvyvYKFbk5u46oQbBvuB9/0w+YsVsxkOv8zVWKpDmUoj4T5ILHoXevA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-replace-supers": "^7.16.5", - "@babel/helper-split-export-declaration": "^7.16.0", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" }, "engines": { @@ -1114,11 +1113,11 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.5.tgz", - "integrity": "sha512-n1+O7xtU5lSLraRzX88CNcpl7vtGdPakKzww74bVwpAIRgz9JVLJJpOLb0uYqcOaXVM0TL6X0RVeIJGD2CnCkg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1128,11 +1127,11 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.5.tgz", - "integrity": "sha512-GuRVAsjq+c9YPK6NeTkRLWyQskDC099XkBSVO+6QzbnOnH2d/4mBVXYStaPrZD3dFRfg00I6BFJ9Atsjfs8mlg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", + "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1142,12 +1141,12 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.5.tgz", - "integrity": "sha512-iQiEMt8Q4/5aRGHpGVK2Zc7a6mx7qEAO7qehgSug3SDImnuMzgmm/wtJALXaz25zUj1PmnNHtShjFgk4PDx4nw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1157,11 +1156,11 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.5.tgz", - "integrity": "sha512-81tijpDg2a6I1Yhj4aWY1l3O1J4Cg/Pd7LfvuaH2VVInAkXtzibz9+zSPdUM1WvuUi128ksstAP0hM5w48vQgg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1171,12 +1170,12 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.5.tgz", - "integrity": "sha512-12rba2HwemQPa7BLIKCzm1pT2/RuQHtSFHdNl41cFiC6oi4tcrp7gjB07pxQvFpcADojQywSjblQth6gJyE6CA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1186,11 +1185,11 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.5.tgz", - "integrity": "sha512-+DpCAJFPAvViR17PIMi9x2AE34dll5wNlXO43wagAX2YcRGgEVHCNFC4azG85b4YyyFarvkc/iD5NPrz4Oneqw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1200,12 +1199,13 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.5.tgz", - "integrity": "sha512-Fuec/KPSpVLbGo6z1RPw4EE1X+z9gZk1uQmnYy7v4xr4TO9p41v1AoUuXEtyqAI7H+xNJYSICzRqZBhDEkd3kQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "dependencies": { - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1215,11 +1215,11 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.5.tgz", - "integrity": "sha512-B1j9C/IfvshnPcklsc93AVLTrNVa69iSqztylZH6qnmiAsDDOmmjEYqOm3Ts2lGSgTSywnBNiqC949VdD0/gfw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1229,11 +1229,11 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.5.tgz", - "integrity": "sha512-d57i3vPHWgIde/9Y8W/xSFUndhvhZN5Wu2TjRrN1MVz5KzdUihKnfDVlfP1U7mS5DNj/WHHhaE4/tTi4hIyHwQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1243,12 +1243,12 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.5.tgz", - "integrity": "sha512-oHI15S/hdJuSCfnwIz+4lm6wu/wBn7oJ8+QrkzPPwSFGXk8kgdI/AIKcbR/XnD1nQVMg/i6eNaXpszbGuwYDRQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1259,13 +1259,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.5.tgz", - "integrity": "sha512-ABhUkxvoQyqhCWyb8xXtfwqNMJD7tx+irIRnUh6lmyFud7Jln1WzONXKlax1fg/ey178EXbs4bSGNd6PngO+SQ==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", + "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-simple-access": "^7.16.0", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1276,14 +1276,14 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.5.tgz", - "integrity": "sha512-53gmLdScNN28XpjEVIm7LbWnD/b/TpbwKbLk6KV4KqC9WyU6rq1jnNmVG6UgAdQZVVGZVoik3DqHNxk4/EvrjA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", + "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", "dependencies": { - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1294,12 +1294,12 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.5.tgz", - "integrity": "sha512-qTFnpxHMoenNHkS3VoWRdwrcJ3FhX567GvDA3hRZKF0Dj8Fmg0UzySZp3AP2mShl/bzcywb/UWAMQIjA1bhXvw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1309,11 +1309,11 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.5.tgz", - "integrity": "sha512-/wqGDgvFUeKELW6ex6QB7dLVRkd5ehjw34tpXu1nhKC0sFfmaLabIswnpf8JgDyV2NeDmZiwoOb0rAmxciNfjA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", + "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1323,11 +1323,11 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.5.tgz", - "integrity": "sha512-ZaIrnXF08ZC8jnKR4/5g7YakGVL6go6V9ql6Jl3ecO8PQaQqFE74CuM384kezju7Z9nGCCA20BqZaR1tJ/WvHg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1337,12 +1337,12 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.5.tgz", - "integrity": "sha512-tded+yZEXuxt9Jdtkc1RraW1zMF/GalVxaVVxh41IYwirdRgyAxxxCKZ9XB7LxZqmsjfjALxupNE1MIz9KH+Zg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-replace-supers": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1352,11 +1352,11 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.5.tgz", - "integrity": "sha512-B3O6AL5oPop1jAVg8CV+haeUte9oFuY85zu0jwnRNZZi3tVAbJriu5tag/oaO2kGaQM/7q7aGPBlTI5/sr9enA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1366,11 +1366,11 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.5.tgz", - "integrity": "sha512-+IRcVW71VdF9pEH/2R/Apab4a19LVvdVsr/gEeotH00vSDVlKD+XgfSIw+cgGWsjDB/ziqGv/pGoQZBIiQVXHg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1380,11 +1380,11 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.5.tgz", - "integrity": "sha512-dHYCOnzSsXFz8UcdNQIHGvg94qPL/teF7CCiCEMRxmA1G2p5Mq4JnKVowCDxYfiQ9D7RstaAp9kwaSI+sXbnhw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", + "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1394,15 +1394,15 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.5.tgz", - "integrity": "sha512-+arLIz1d7kmwX0fKxTxbnoeG85ONSnLpvdODa4P3pc1sS7CV1hfmtYWufkW/oYsPnkDrEeQFxhUWcFnrXW7jQQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", + "integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/plugin-syntax-jsx": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1412,11 +1412,11 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.5.tgz", - "integrity": "sha512-uQSLacMZSGLCxOw20dzo1dmLlKkd+DsayoV54q3MHXhbqgPzoiGerZQgNPl/Ro8/OcXV2ugfnkx+rxdS0sN5Uw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", + "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.16.5" + "@babel/plugin-transform-react-jsx": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1426,12 +1426,12 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.5.tgz", - "integrity": "sha512-0nYU30hCxnCVCbRjSy9ahlhWZ2Sn6khbY4FqR91W+2RbSqkWEbVu2gXh45EqNy4Bq7sRU+H4i0/6YKwOSzh16A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", + "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1441,9 +1441,9 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.5.tgz", - "integrity": "sha512-2z+it2eVWU8TtQQRauvGUqZwLy4+7rTfo6wO4npr+fvvN1SW30ZF3O/ZRCNmTuu4F5MIP8OJhXAhRV5QMJOuYg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", + "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", "dependencies": { "regenerator-transform": "^0.14.2" }, @@ -1455,11 +1455,11 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.5.tgz", - "integrity": "sha512-aIB16u8lNcf7drkhXJRoggOxSTUAuihTSTfAcpynowGJOZiGf+Yvi7RuTwFzVYSYPmWyARsPqUGoZWWWxLiknw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1469,11 +1469,11 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.5.tgz", - "integrity": "sha512-ZbuWVcY+MAXJuuW7qDoCwoxDUNClfZxoo7/4swVbOW1s/qYLOMHlm9YRWMsxMFuLs44eXsv4op1vAaBaBaDMVg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1483,11 +1483,11 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.5.tgz", - "integrity": "sha512-5d6l/cnG7Lw4tGHEoga4xSkYp1euP7LAtrah1h1PgJ3JY7yNsjybsxQAnVK4JbtReZ/8z6ASVmd3QhYYKLaKZw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" }, "engines": { @@ -1498,11 +1498,11 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.5.tgz", - "integrity": "sha512-usYsuO1ID2LXxzuUxifgWtJemP7wL2uZtyrTVM4PKqsmJycdS4U4mGovL5xXkfUheds10Dd2PjoQLXw6zCsCbg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1512,11 +1512,11 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.5.tgz", - "integrity": "sha512-gnyKy9RyFhkovex4BjKWL3BVYzUDG6zC0gba7VMLbQoDuqMfJ1SDXs8k/XK41Mmt1Hyp4qNAvGFb9hKzdCqBRQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1526,11 +1526,11 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.5.tgz", - "integrity": "sha512-ldxCkW180qbrvyCVDzAUZqB0TAeF8W/vGJoRcaf75awm6By+PxfJKvuqVAnq8N9wz5Xa6mSpM19OfVKKVmGHSQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1540,11 +1540,11 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.5.tgz", - "integrity": "sha512-shiCBHTIIChGLdyojsKQjoAyB8MBwat25lKM7MJjbe1hE0bgIppD+LX9afr41lLHOhqceqeWl4FkLp+Bgn9o1Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1554,12 +1554,12 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.5.tgz", - "integrity": "sha512-GTJ4IW012tiPEMMubd7sD07iU9O/LOo8Q/oU4xNhcaq0Xn8+6TcUQaHtC8YxySo1T+ErQ8RaWogIEeFhKGNPzw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" @@ -1689,14 +1689,14 @@ } }, "node_modules/@babel/register": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.5.tgz", - "integrity": "sha512-NpluD+cToBiZiDsG3y9rtIcqDyivsahpaM9csfyfiq1qQWduSmihUZ+ruIqqSDGjZKZMJfgAElo9x2YWlOQuRw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.17.0.tgz", + "integrity": "sha512-UNZsMAZ7uKoGHo1HlEXfteEOYssf64n/PNLHGqOKq/bgYcu/4LrQWAHJwSCb3BRZK8Hi5gkJdRcwrGTO2wtRCg==", "dependencies": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", "make-dir": "^2.1.0", - "pirates": "^4.0.0", + "pirates": "^4.0.5", "source-map-support": "^0.5.16" }, "engines": { @@ -1707,9 +1707,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", - "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", + "integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -1718,12 +1718,12 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.5.tgz", - "integrity": "sha512-F1pMwvTiUNSAM8mc45kccMQxj31x3y3P+tA/X8hKNWp3/hUsxdGxZ3D3H8JIkxtfA8qGkaBTKvcmvStaYseAFw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.0.tgz", + "integrity": "sha512-qeydncU80ravKzovVncW3EYaC1ji3GpntdPgNcJy9g7hHSY6KX+ne1cbV3ov7Zzm4F1z0+QreZPCuw1ynkmYNg==", "dev": true, "dependencies": { - "core-js-pure": "^3.19.0", + "core-js-pure": "^3.20.2", "regenerator-runtime": "^0.13.4" }, "engines": { @@ -1731,31 +1731,31 @@ } }, "node_modules/@babel/template": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz", - "integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "dependencies": { - "@babel/code-frame": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz", - "integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", + "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", "dependencies": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.5", - "@babel/types": "^7.16.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.0", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.0", + "@babel/types": "^7.17.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1764,11 +1764,11 @@ } }, "node_modules/@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1786,16 +1786,16 @@ } }, "node_modules/@date-io/core": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.11.0.tgz", - "integrity": "sha512-DvPBnNoeuLaoSJZaxgpu54qzRhRKjSYVyQjhznTFrllKuDpm0sDFjHo6lvNLCM/cfMx2gb2PM2zY2kc9C8nmuw==" + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.13.1.tgz", + "integrity": "sha512-pVI9nfkf2qClb2Cxdq0Q4zJhdawMG4ybWZUVGifT78FDwzRMX2SwXBb55s5NRJk0HcIicDuxktmCtemZqMH1Zg==" }, "node_modules/@date-io/date-fns": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.11.0.tgz", - "integrity": "sha512-mPQ71plBeFrArvBSHtjWMHXA89IUbZ6kuo2dsjlRC/1uNOybo91spIb+wTu03NxKTl8ut07s0jJ9svF71afpRg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.13.1.tgz", + "integrity": "sha512-8fmfwjiLMpFLD+t4NBwDx0eblWnNcgt4NgfT/uiiQTGI81fnPu9tpBMYdAcuWxaV7LLpXgzLBx1SYWAMDVUDQQ==", "dependencies": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" }, "peerDependencies": { "date-fns": "^2.0.0" @@ -1807,11 +1807,11 @@ } }, "node_modules/@date-io/dayjs": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.11.0.tgz", - "integrity": "sha512-w67vRK56NZJIKhJM/CrNbfnIcuMvR3ApfxzNZiCZ5w29sxgBDeKuX4M+P7A9r5HXOMGcsOcpgaoTDINNGkdpGQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.13.1.tgz", + "integrity": "sha512-5bL4WWWmlI4uGZVScANhHJV7Mjp93ec2gNeUHDqqLaMZhp51S0NgD25oqj/k0LqBn1cdU2MvzNpk/ObMmVv5cQ==", "dependencies": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" }, "peerDependencies": { "dayjs": "^1.8.17" @@ -1823,11 +1823,11 @@ } }, "node_modules/@date-io/luxon": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.11.1.tgz", - "integrity": "sha512-JUXo01kdPQxLORxqdENrgdUhooKgDUggsNRSdi2BcUhASIY2KGwwWXu8ikVHHGkw+DUF4FOEKGfkQd0RHSvX6g==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.13.1.tgz", + "integrity": "sha512-yG+uM7lXfwLyKKEwjvP8oZ7qblpmfl9gxQYae55ifbwiTs0CoCTkYkxEaQHGkYtTqGTzLqcb0O9Pzx6vgWg+yg==", "dependencies": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" }, "peerDependencies": { "luxon": "^1.21.3 || ^2.x" @@ -1839,11 +1839,11 @@ } }, "node_modules/@date-io/moment": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.11.0.tgz", - "integrity": "sha512-QSL+83qezQ9Ty0dtFgAkk6eC0GMl/lgYfDajeVUDB3zVA2A038hzczRLBg29ifnBGhQMPABxuOafgWwhDjlarg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.13.1.tgz", + "integrity": "sha512-XX1X/Tlvl3TdqQy2j0ZUtEJV6Rl8tOyc5WOS3ki52He28Uzme4Ro/JuPWTMBDH63weSWIZDlbR7zBgp3ZA2y1A==", "dependencies": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" }, "peerDependencies": { "moment": "^2.24.0" @@ -1863,9 +1863,9 @@ } }, "node_modules/@emotion/babel-plugin": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.1.tgz", - "integrity": "sha512-K3/6Y+J/sIAjplf3uIteWLhPuOyuMNnE+iyYnTF/m294vc6IL90kTHp7y8ldZYbpKlP17rpOWDKM9DvTcrOmNQ==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz", + "integrity": "sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==", "dependencies": { "@babel/helper-module-imports": "^7.12.13", "@babel/plugin-syntax-jsx": "^7.12.13", @@ -2011,6 +2011,15 @@ "node": "^12 || ^14 || ^16 || ^17" } }, + "node_modules/@es-joy/jsdoccomment/node_modules/jsdoc-type-pratt-parser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.0.0.tgz", + "integrity": "sha512-sUuj2j48wxrEpbFjDp1sAesAxPiLT+z0SWVmMafyIINs6Lj5gIPKh3VrkBZu4E/Dv+wHpOot0m6H8zlHQjwqeQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -2032,9 +2041,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2046,24 +2055,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@hookform/devtools": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@hookform/devtools/-/devtools-4.0.1.tgz", - "integrity": "sha512-xVPIK8FGi3Fp7q9qxWrXLwiGxoZzn6g2ihIBQG0ddpiVSAAsH21Jh39tyyYWtkHZkTo9deiPs98SwXnN48hMjg==", - "dependencies": { - "@emotion/react": "^11.1.5", - "@emotion/styled": "^11.3.0", - "@types/lodash": "^4.14.168", - "little-state-machine": "^4.1.0", - "lodash": "^4.17.21", - "react-simple-animate": "^3.3.12" - }, - "peerDependencies": { - "react": ">=17.0.2", - "react-dom": ">=17.0.2", - "react-hook-form": "^7.13.0" - } - }, "node_modules/@hookform/resolvers": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.2.tgz", @@ -2304,15 +2295,15 @@ } }, "node_modules/@mui/lab/node_modules/@mui/system": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.2.4.tgz", - "integrity": "sha512-08WrDLzmY0/ag5wSzT0Qf2DkuPHdqkWbDUOIVs0VIkaq8tRH+EtnnLxuqyf8WLcytJZIcKcoLQDLWqbFivZ9lA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.4.0.tgz", + "integrity": "sha512-LX7g5gK5yCwiueSUVG73uVNc0yeHjsWUIFLrnPjP3m+J7O38RkPqyao5nZahhaSL1PGNbR9+zfkxljXthO9QqA==", "dependencies": { - "@babel/runtime": "^7.16.3", - "@mui/private-theming": "^5.2.3", - "@mui/styled-engine": "^5.2.4", + "@babel/runtime": "^7.16.7", + "@mui/private-theming": "^5.3.0", + "@mui/styled-engine": "^5.3.0", "@mui/types": "^7.1.0", - "@mui/utils": "^5.2.3", + "@mui/utils": "^5.3.0", "clsx": "^1.1.1", "csstype": "^3.0.10", "prop-types": "^15.7.2" @@ -2328,7 +2319,7 @@ "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", "@types/react": "^16.8.6 || ^17.0.0", - "react": "^17.0.2" + "react": "^17.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -2427,12 +2418,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.2.3.tgz", - "integrity": "sha512-Lc1Cmu8lSsYZiXADi9PBb17Ho82ZbseHQujUFAcp6bCJ5x/d+87JYCIpCBMagPu/isRlFCwbziuXPmz7WOzJPQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.3.0.tgz", + "integrity": "sha512-EBobUEyM9fMnteKrVPp8pTMUh81xXakyfdpkoh7Y19q9JpD2eh7QGAQVJVj0JBFlcUJD60NIE4K8rdokrRmLwg==", "dependencies": { - "@babel/runtime": "^7.16.3", - "@mui/utils": "^5.2.3", + "@babel/runtime": "^7.16.7", + "@mui/utils": "^5.3.0", "prop-types": "^15.7.2" }, "engines": { @@ -2444,7 +2435,7 @@ }, "peerDependencies": { "@types/react": "^16.8.6 || ^17.0.0", - "react": "^17.0.2" + "react": "^17.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -2453,12 +2444,12 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.2.4.tgz", - "integrity": "sha512-tlilkVsAR+MeWIPILzj1uGjiy5tKONZgblXY49LECUNF7u7aTDszqmv0hRG+1IAZjNts+ox8XAlldPNfj+OKvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.3.0.tgz", + "integrity": "sha512-I4YemFy9WnCLUdZ5T+6egpzc8e7Jq/uh9AJ3QInZHbyNu/9I2SWvNn7vHjWOT/D8Y8LMzIOhu5WwZbzjez7YRw==", "dependencies": { - "@babel/runtime": "^7.16.3", - "@emotion/cache": "^11.6.0", + "@babel/runtime": "^7.16.7", + "@emotion/cache": "^11.7.1", "prop-types": "^15.7.2" }, "engines": { @@ -2471,7 +2462,7 @@ "peerDependencies": { "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", - "react": "^17.0.2" + "react": "^17.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -2575,11 +2566,11 @@ } }, "node_modules/@mui/utils": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.2.3.tgz", - "integrity": "sha512-sQujlajIS0zQKcGIS6tZR0L1R+ib26B6UtuEn+cZqwKHsPo3feuS+SkdscYBdcCdMbrZs4gj8WIJHl2z6tbSzQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.3.0.tgz", + "integrity": "sha512-O/E9IQKPMg0OrN7+gkn7Ga5o5WA2iXQGdyqNBFPNrYzxOvwzsEtM5K7MtTCGGYKFe8mhTRM0ZOjh5OM0dglw+Q==", "dependencies": { - "@babel/runtime": "^7.16.3", + "@babel/runtime": "^7.16.7", "@types/prop-types": "^15.7.4", "@types/react-is": "^16.7.1 || ^17.0.0", "prop-types": "^15.7.2", @@ -2593,7 +2584,7 @@ "url": "https://opencollective.com/mui" }, "peerDependencies": { - "react": "^17.0.2" + "react": "^17.0.0" } }, "node_modules/@mui/utils/node_modules/react-is": { @@ -2699,9 +2690,9 @@ } }, "node_modules/@popperjs/core": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz", - "integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz", + "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -2716,7 +2707,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.7.1.tgz", "integrity": "sha512-wXwXYjBVz/ItxB7SMzEAMmEE/FBiY1ze18N+VVVX7NtVbRUrdOGKhpQMHivIJfkbJvSdLUU923a/yAagJQzY0Q==", - "license": "MIT", "dependencies": { "immer": "^9.0.7", "redux": "^4.1.2", @@ -2881,9 +2871,9 @@ "integrity": "sha512-T4aL2ZzaILkLGKbxssipYVRs8334PSR9FQzTGftZbc3jIPGkiXXS7qUCh8/q8UWFzxBZQ92dvR0v7+AM9wL2PA==" }, "node_modules/@types/d3-ease": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-2.0.1.tgz", - "integrity": "sha512-Af1ftZXv82ktPCk1+Vxe7f+VSfxDsQ1mwwakDl17+UzI/ii3vsDIAzaBDDSEQd2Cg9BYPTSx8wXH8rJNDuSjeg==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-2.0.2.tgz", + "integrity": "sha512-29Y73Tg6o6aL+3/S/kEun84m5BO4bjRNau6pMWv9N9rZHcJv/O/07mW6EjqxrePZZS64fj0wiB5LMHr4Jzf3eQ==" }, "node_modules/@types/d3-fetch": { "version": "2.0.2", @@ -3003,18 +2993,18 @@ } }, "node_modules/@types/eslint": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", - "integrity": "sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "node_modules/@types/eslint-scope": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.2.tgz", - "integrity": "sha512-TzgYCWoPiTeRg6RQYgtuW7iODtVoKu3RVL72k3WohqhjfaOLK5Mg2T4Tg1o2bSfu0vPkoI48wdQFv5b/Xe04wQ==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -3064,9 +3054,9 @@ "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" }, "node_modules/@types/node": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", - "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==" + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", + "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -3079,9 +3069,9 @@ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "node_modules/@types/react": { - "version": "17.0.37", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.37.tgz", - "integrity": "sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==", + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", + "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3097,9 +3087,9 @@ } }, "node_modules/@types/react-redux": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz", - "integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==", + "version": "7.1.22", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", + "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -3252,18 +3242,18 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "peerDependencies": { "webpack": "4.x.x || 5.x.x", "webpack-cli": "4.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "dependencies": { "envinfo": "^7.7.3" }, @@ -3272,9 +3262,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "peerDependencies": { "webpack-cli": "4.x.x" }, @@ -3295,12 +3285,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -3619,9 +3609,9 @@ } }, "node_modules/async": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", - "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -3661,9 +3651,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "node_modules/axe-core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", - "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", + "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", "dev": true, "engines": { "node": ">=4" @@ -3673,7 +3663,6 @@ "version": "0.25.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "license": "MIT", "dependencies": { "follow-redirects": "^1.14.7" } @@ -4251,9 +4240,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001287", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001287.tgz", - "integrity": "sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==", + "version": "1.0.30001307", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001307.tgz", + "integrity": "sha512-+MXEMczJ4FuxJAUp0jvAl6Df0NI/OfW1RWEE61eSmzS7hw6lz4IKutbhbXendwq8BljfFuHtu26VWsg4afQ7Ng==", "funding": { "type": "opencollective", "url": "https://opencollective.com/browserslist" @@ -4286,9 +4275,15 @@ } }, "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "optional": true, "dependencies": { "anymatch": "~3.1.2", @@ -4655,9 +4650,9 @@ } }, "node_modules/core-js-compat": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.0.tgz", - "integrity": "sha512-relrah5h+sslXssTTOkvqcC/6RURifB0W5yhYBdBkaPYa5/2KBMiog3XiD+s3TwEHWxInWVv4Jx2/Lw0vng+IQ==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", + "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", "dependencies": { "browserslist": "^4.19.1", "semver": "7.0.0" @@ -4676,9 +4671,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.20.0.tgz", - "integrity": "sha512-qsrbIwWSEEYOM7z616jAVgwhuDDtPLwZSpUsU3vyUkHYqKTf/uwOJBZg2V7lMurYWkpVlaVOxBrfX0Q3ppvjfg==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.0.tgz", + "integrity": "sha512-VaJUunCZLnxuDbo1rNOzwbet9E1K9joiXS5+DQMPtgxd24wfsZbJZMMfQLGYMlCUvSxLfsRUUhoOR2x28mFfeg==", "dev": true, "hasInstallScript": true, "funding": { @@ -4965,9 +4960,9 @@ } }, "node_modules/damerau-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", - "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, "node_modules/dashdash": { @@ -5197,9 +5192,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/electron-to-chromium": { - "version": "1.4.23", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.23.tgz", - "integrity": "sha512-q3tB59Api3+DMbLnDPkW/UBHBO7KTGcF+rDCeb0GAGyqFj562s6y+c/2tDKTS/y5lbC+JOvT4MSUALJLPqlcSA==" + "version": "1.4.65", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.65.tgz", + "integrity": "sha512-0/d8Skk8sW3FxXP0Dd6MnBlrwx7Qo9cqQec3BlIAlvKnrmS3pHsIbaroEi+nd0kZkGpQ6apMEre7xndzjlEnLw==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -5325,9 +5320,9 @@ } }, "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "engines": { "node": ">= 0.6" } @@ -5590,6 +5585,60 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/eslint-config-opennebula/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-config-opennebula/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-opennebula/node_modules/eslint-plugin-import": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", + "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.1", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-config-opennebula/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, "node_modules/eslint-config-prettier": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", @@ -5706,14 +5755,13 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", - "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "dev": true, "dependencies": { "debug": "^3.2.7", - "find-up": "^2.1.0", - "pkg-dir": "^2.0.0" + "find-up": "^2.1.0" }, "engines": { "node": ">=4" @@ -5821,24 +5869,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", - "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", + "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", "dev": true, + "peer": true, "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.1", + "eslint-module-utils": "^2.7.2", "has": "^1.0.3", "is-core-module": "^2.8.0", "is-glob": "^4.0.3", "minimatch": "^3.0.4", "object.values": "^1.1.5", "resolve": "^1.20.0", - "tsconfig-paths": "^3.11.0" + "tsconfig-paths": "^3.12.0" }, "engines": { "node": ">=4" @@ -5852,6 +5901,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -5861,6 +5911,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -5872,7 +5923,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "dev": true, + "peer": true }, "node_modules/eslint-plugin-jsdoc": { "version": "37.0.3", @@ -5959,9 +6011,9 @@ } }, "node_modules/eslint-plugin-node/node_modules/ignore": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { "node": ">= 4" @@ -6174,9 +6226,9 @@ "dev": true }, "node_modules/eslint/node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -6446,9 +6498,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -6457,7 +6509,7 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-json-stable-stringify": { @@ -6587,73 +6639,6 @@ "node": ">=6" } }, - "node_modules/find-cache-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-cache-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-cache-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-cache-dir/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -6698,9 +6683,9 @@ } }, "node_modules/flatted": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", - "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "node_modules/fn.name": { @@ -7001,15 +6986,15 @@ } }, "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -7020,9 +7005,9 @@ } }, "node_modules/globby/node_modules/ignore": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "engines": { "node": ">= 4" } @@ -7036,9 +7021,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, "node_modules/graphlib": { "version": "2.1.8", @@ -7396,9 +7381,9 @@ } }, "node_modules/immer": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz", - "integrity": "sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA==", + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -7425,9 +7410,9 @@ } }, "node_modules/import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -7437,6 +7422,9 @@ }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/import-local/node_modules/find-up": { @@ -7632,9 +7620,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dependencies": { "has": "^1.0.3" }, @@ -7834,9 +7822,9 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "node_modules/jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.0.tgz", + "integrity": "sha512-8OEHiPNOPTfaWnJ2SUHM8fmgeGq37uuGsQBvGKQJl1f+6WIy6g7G3fE2ruI5294bUKUI9FaCWt5hDvO8HSwsSg==", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -7892,9 +7880,9 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "node_modules/jsdoc-type-pratt-parser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.0.0.tgz", - "integrity": "sha512-sUuj2j48wxrEpbFjDp1sAesAxPiLT+z0SWVmMafyIINs6Lj5gIPKh3VrkBZu4E/Dv+wHpOot0m6H8zlHQjwqeQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.2.2.tgz", + "integrity": "sha512-zRokSWcPLSWkoNzsWn9pq7YYSwDhKyEe+cJYT2qaPqLOOJb5sFSi46BPj81vP+e8chvCNdQL9RG86Bi9EI6MDw==", "dev": true, "engines": { "node": ">=12.0.0" @@ -8194,14 +8182,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "node_modules/little-state-machine": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/little-state-machine/-/little-state-machine-4.2.0.tgz", - "integrity": "sha512-UMWelGx2fJfUC3KGy2FajC+H6+DJ9nCHJeolm4pq0Qldks+MemC6/6PTIhRqDpaBkna2TMG4bewidrt393cSsw==", - "peerDependencies": { - "react": "^16.8.0 || ^17" - } - }, "node_modules/loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -8319,11 +8299,11 @@ "dev": true }, "node_modules/logform": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", - "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.2.tgz", + "integrity": "sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA==", "dependencies": { - "colors": "^1.2.1", + "colors": "1.4.0", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^1.1.0", @@ -8411,9 +8391,9 @@ } }, "node_modules/memfs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.0.tgz", - "integrity": "sha512-o/RfP0J1d03YwsAxyHxAYs2kyJp55AFkMazlFAZFR2I2IXkxiUTXRabJ6RmNNCQ83LAD2jy52Khj0m3OffpNdA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", + "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", "dev": true, "dependencies": { "fs-monkey": "1.0.3" @@ -8666,9 +8646,9 @@ "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" }, "node_modules/nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -8707,9 +8687,9 @@ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -8911,9 +8891,9 @@ } }, "node_modules/object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9345,9 +9325,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "engines": { "node": ">=8.6" }, @@ -9364,72 +9344,78 @@ } }, "node_modules/pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "engines": { "node": ">= 6" } }, "node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dependencies": { - "find-up": "^2.1.0" + "find-up": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-dir/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dependencies": { - "locate-path": "^2.0.0" + "locate-path": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-dir/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dependencies": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/pkg-dir/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dependencies": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-dir/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dependencies": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" + } + }, + "node_modules/pkg-dir/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" } }, "node_modules/pkg-up": { @@ -9508,13 +9494,13 @@ } }, "node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "dependencies": { - "nanoid": "^3.1.30", + "nanoid": "^3.2.0", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -9580,9 +9566,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz", - "integrity": "sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -9690,9 +9676,9 @@ } }, "node_modules/property-expr": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", - "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", + "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -10282,15 +10268,6 @@ "isarray": "0.0.1" } }, - "node_modules/react-simple-animate": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/react-simple-animate/-/react-simple-animate-3.3.12.tgz", - "integrity": "sha512-lFXjxD6ficcpOMsHfcDs1jqdkCve6jNlJnubOCzVOLswFDRANsaLN4KwpezDuliEFz8Q1zyj4J7Tmj3KMRnPcg==", - "peerDependencies": { - "react": "^16.8.0 || ^17", - "react-dom": "^16.8.0 || ^17" - } - }, "node_modules/react-table": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.7.0.tgz", @@ -10395,9 +10372,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "node_modules/regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "dependencies": { "regenerate": "^1.4.2" }, @@ -10419,9 +10396,9 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", + "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", @@ -10447,14 +10424,14 @@ } }, "node_modules/regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "dependencies": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" }, @@ -10472,14 +10449,14 @@ } }, "node_modules/regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" }, "node_modules/regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "dependencies": { "jsesc": "~0.5.0" }, @@ -10527,9 +10504,9 @@ } }, "node_modules/request/node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "engines": { "node": ">=0.6" } @@ -10576,12 +10553,16 @@ "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10877,9 +10858,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/simple-concat": { "version": "1.0.1", @@ -10901,9 +10882,9 @@ ] }, "node_modules/simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "dependencies": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -11057,9 +11038,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "engines": { "node": ">=0.10.0" } @@ -11120,9 +11101,9 @@ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" }, "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -11403,10 +11384,21 @@ "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==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/table": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", - "integrity": "sha512-LFNeryOqiQHqCVKzhkymKwt6ozeRhlm8IL1mE8rNUurkir4heF6PzMyRgaTa4tlyPTGGgXuvVOF/OLWiH09Lqw==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", "dev": true, "dependencies": { "ajv": "^8.0.1", @@ -11420,9 +11412,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", - "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -11513,9 +11505,9 @@ } }, "node_modules/terser-webpack-plugin/node_modules/acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "optional": true, "peer": true, "bin": { @@ -12182,9 +12174,9 @@ } }, "node_modules/webpack/node_modules/acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "bin": { "acorn": "bin/acorn" }, @@ -12289,13 +12281,13 @@ } }, "node_modules/winston-transport": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz", - "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", "dependencies": { - "logform": "^2.2.0", - "readable-stream": "^3.4.0", - "triple-beam": "^1.2.0" + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" }, "engines": { "node": ">= 6.4.0" @@ -12563,17 +12555,17 @@ } }, "@babel/code-frame": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", - "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", "requires": { - "@babel/highlight": "^7.16.0" + "@babel/highlight": "^7.16.7" } }, "@babel/compat-data": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", - "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==" + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", + "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==" }, "@babel/core": { "version": "7.15.8", @@ -12609,64 +12601,64 @@ } }, "@babel/generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", - "integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", + "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", "requires": { - "@babel/types": "^7.16.0", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz", - "integrity": "sha512-ItmYF9vR4zA8cByDocY05o0LGUkp1zhbTQOH1NFyl5xXEqlTJQCEJjieriw+aFpxo16swMxUnUiKS7a/r4vtHg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", + "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.5.tgz", - "integrity": "sha512-3JEA9G5dmmnIWdzaT9d0NmFRgYnWUThLsDaL7982H0XqqWr56lRrsmwheXFMjR+TMl7QMBb6mzy9kvgr1lRLUA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", + "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-explode-assignable-expression": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-compilation-targets": { - "version": "7.16.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz", - "integrity": "sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", "requires": { - "@babel/compat-data": "^7.16.0", - "@babel/helper-validator-option": "^7.14.5", + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", "browserslist": "^4.17.5", "semver": "^6.3.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.5.tgz", - "integrity": "sha512-NEohnYA7mkB8L5JhU7BLwcBdU3j83IziR9aseMueWGeAjblbul3zzb8UvJ3a1zuBiqCMObzCJHFqKIQE6hTVmg==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", + "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-member-expression-to-functions": "^7.16.5", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-replace-supers": "^7.16.5", - "@babel/helper-split-export-declaration": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.0.tgz", - "integrity": "sha512-3DyG0zAFAZKcOp7aVr33ddwkxJ0Z0Jr5V99y3I690eYLpukJsJvAbzTy1ewoCqsML8SbIrjH14Jc/nSQ4TvNPA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", + "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "regexpu-core": "^4.7.1" + "@babel/helper-annotate-as-pure": "^7.16.7", + "regexpu-core": "^5.0.1" } }, "@babel/helper-define-polyfill-provider": { @@ -12685,119 +12677,119 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz", - "integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-explode-assignable-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz", - "integrity": "sha512-Hk2SLxC9ZbcOhLpg/yMznzJ11W++lg5GMbxt1ev6TXUiJB0N42KPC+7w8a+eWGuqDnUYuwStJoZHM7RgmIOaGQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", + "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-function-name": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", - "integrity": "sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", "requires": { - "@babel/helper-get-function-arity": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-get-function-arity": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz", - "integrity": "sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-hoist-variables": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz", - "integrity": "sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.5.tgz", - "integrity": "sha512-7fecSXq7ZrLE+TWshbGT+HyCLkxloWNhTbU2QM1NTI/tDqyf0oZiMcEfYtDuUDCo528EOlt39G1rftea4bRZIw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", + "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-imports": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", - "integrity": "sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-module-transforms": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz", - "integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", "requires": { - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-simple-access": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/helper-validator-identifier": "^7.15.7", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-optimise-call-expression": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz", - "integrity": "sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", + "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-plugin-utils": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", - "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", + "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==" }, "@babel/helper-remap-async-to-generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz", - "integrity": "sha512-X+aAJldyxrOmN9v3FKp+Hu1NO69VWgYgDGq6YDykwRPzxs5f2N+X988CBXS7EQahDU+Vpet5QYMqLk+nsp+Qxw==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", + "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-wrap-function": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-wrap-function": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helper-replace-supers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.5.tgz", - "integrity": "sha512-ao3seGVa/FZCMCCNDuBcqnBFSbdr8N2EW35mzojx3TwfIbdPmNK+JV6+2d5bR0Z71W5ocLnQp9en/cTF7pBJiQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", + "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", "requires": { - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-member-expression-to-functions": "^7.16.5", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/helper-simple-access": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz", - "integrity": "sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-skip-transparent-expression-wrappers": { @@ -12809,50 +12801,50 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz", - "integrity": "sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", "requires": { - "@babel/types": "^7.16.0" + "@babel/types": "^7.16.7" } }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" }, "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" }, "@babel/helper-wrap-function": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz", - "integrity": "sha512-2J2pmLBqUqVdJw78U0KPNdeE2qeuIyKoG4mKV7wAq3mc4jJG282UgjZw4ZYDnqiWQuS3Y3IYdF/AQ6CpyBV3VA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", + "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", "requires": { - "@babel/helper-function-name": "^7.16.0", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-function-name": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.8", + "@babel/types": "^7.16.8" } }, "@babel/helpers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", - "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.0.tgz", + "integrity": "sha512-Xe/9NFxjPwELUvW2dsukcMZIp6XwPSbI4ojFBJuX5ramHuVE22SVcZIwqzdWo5uCgeTXW8qV97lMvSOjq+1+nQ==", "requires": { - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.17.0", + "@babel/types": "^7.17.0" } }, "@babel/highlight": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", - "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } @@ -12871,26 +12863,26 @@ } }, "@babel/parser": { - "version": "7.16.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", - "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==" + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", + "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==" }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.0.tgz", - "integrity": "sha512-4tcFwwicpWTrpl9qjf7UsoosaArgImF85AxqCRZlgc3IQDvkUHjJpruXAL58Wmj+T6fypWTC/BakfEkwIL/pwA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", + "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", "requires": { - "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0" + "@babel/plugin-proposal-optional-chaining": "^7.16.7" }, "dependencies": { "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.5.tgz", - "integrity": "sha512-kzdHgnaXRonttiTfKYnSVafbWngPPr2qKw9BWYBESl91W54e+9R5pP70LtWxV56g0f05f/SQrwHYkfvbwcdQ/A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", + "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } @@ -12898,12 +12890,12 @@ } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.5.tgz", - "integrity": "sha512-C/FX+3HNLV6sz7AqbTQqEo1L9/kfrKjxcVtgyBCmvIgOjvuBVUWooDoi7trsLxOzCEo5FccjRvKHkfDsJFZlfA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", + "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-remap-async-to-generator": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, @@ -12917,48 +12909,48 @@ } }, "@babel/plugin-proposal-class-static-block": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.5.tgz", - "integrity": "sha512-EEFzuLZcm/rNJ8Q5krK+FRKdVkd6FjfzT9tuSZql9sQn64K0hHA2KLJ0DqVot9/iV6+SsuadC5yI39zWnm+nmQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", + "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.5.tgz", - "integrity": "sha512-P05/SJZTTvHz79LNYTF8ff5xXge0kk5sIIWAypcWgX4BTRUgyHc8wRxJ/Hk+mU0KXldgOOslKaeqnhthcDJCJQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", + "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.5.tgz", - "integrity": "sha512-i+sltzEShH1vsVydvNaTRsgvq2vZsfyrd7K7vPLUU/KgS0D5yZMe6uipM0+izminnkKrEfdUnz7CxMRb6oHZWw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", + "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.5.tgz", - "integrity": "sha512-QQJueTFa0y9E4qHANqIvMsuxM/qcLQmKttBACtPCQzGUEizsXDACGonlPiSwynHfOa3vNw0FPMVvQzbuXwh4SQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", + "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.5.tgz", - "integrity": "sha512-xqibl7ISO2vjuQM+MzR3rkd0zfNWltk7n9QhaD8ghMmMceVguYrNDt7MikRyj4J4v3QehpnrU8RYLnC7z/gZLA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", + "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, @@ -12972,11 +12964,11 @@ } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.5.tgz", - "integrity": "sha512-DvB9l/TcsCRvsIV9v4jxR/jVP45cslTVC0PMVHvaJhhNuhn2Y1SOhCSFlPK777qLB5wb8rVDaNoqMTyOqtY5Iw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", + "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, @@ -12993,11 +12985,11 @@ } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.5.tgz", - "integrity": "sha512-ihCMxY1Iljmx4bWy/PIMJGXN4NS4oUj1MKynwO07kiKms23pNvIn1DMB92DNB2R0EA882sw0VXIelYGdtF7xEQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", + "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, @@ -13012,32 +13004,32 @@ } }, "@babel/plugin-proposal-private-methods": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.5.tgz", - "integrity": "sha512-+yFMO4BGT3sgzXo+lrq7orX5mAZt57DwUK6seqII6AcJnJOIhBJ8pzKH47/ql/d426uQ7YhN8DpUFirQzqYSUA==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-class-features-plugin": "^7.16.10", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.5.tgz", - "integrity": "sha512-+YGh5Wbw0NH3y/E5YMu6ci5qTDmAEVNoZ3I54aB6nVEOZ5BQ7QJlwKq5pYVucQilMByGn/bvX0af+uNaPRCabA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", + "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-create-class-features-plugin": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.5.tgz", - "integrity": "sha512-s5sKtlKQyFSatt781HQwv1hoM5BQ9qRH30r+dK56OLDsHmV74mzwJNX7R1yMuE7VZKG5O6q/gmOGSAO6ikTudg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", + "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-async-generators": { @@ -13089,11 +13081,11 @@ } }, "@babel/plugin-syntax-jsx": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.5.tgz", - "integrity": "sha512-42OGssv9NPk4QHKVgIHlzeLgPOW5rGgfV5jzG90AhcXXIv6hu/eqj63w4VgvRxdvZY3AlYeDgPiSJ3BqAd1Y6Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", + "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-syntax-logical-assignment-operators": { @@ -13161,321 +13153,322 @@ } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.5.tgz", - "integrity": "sha512-8bTHiiZyMOyfZFULjsCnYOWG059FVMes0iljEHSfARhNgFfpsqE92OrCffv3veSw9rwMkYcFe9bj0ZoXU2IGtQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", + "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.5.tgz", - "integrity": "sha512-TMXgfioJnkXU+XRoj7P2ED7rUm5jbnDWwlCuFVTpQboMfbSya5WrmubNBAMlk7KXvywpo8rd8WuYZkis1o2H8w==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", + "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", "requires": { - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-remap-async-to-generator": "^7.16.5" + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-remap-async-to-generator": "^7.16.8" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.5.tgz", - "integrity": "sha512-BxmIyKLjUGksJ99+hJyL/HIxLIGnLKtw772zYDER7UuycDZ+Xvzs98ZQw6NGgM2ss4/hlFAaGiZmMNKvValEjw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", + "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.5.tgz", - "integrity": "sha512-JxjSPNZSiOtmxjX7PBRBeRJTUKTyJ607YUYeT0QJCNdsedOe+/rXITjP08eG8xUpsLfPirgzdCFN+h0w6RI+pQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", + "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-classes": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.5.tgz", - "integrity": "sha512-DzJ1vYf/7TaCYy57J3SJ9rV+JEuvmlnvvyvYKFbk5u46oQbBvuB9/0w+YsVsxkOv8zVWKpDmUoj4T5ILHoXevA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", + "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-optimise-call-expression": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-replace-supers": "^7.16.5", - "@babel/helper-split-export-declaration": "^7.16.0", + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-optimise-call-expression": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.5.tgz", - "integrity": "sha512-n1+O7xtU5lSLraRzX88CNcpl7vtGdPakKzww74bVwpAIRgz9JVLJJpOLb0uYqcOaXVM0TL6X0RVeIJGD2CnCkg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", + "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-destructuring": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.5.tgz", - "integrity": "sha512-GuRVAsjq+c9YPK6NeTkRLWyQskDC099XkBSVO+6QzbnOnH2d/4mBVXYStaPrZD3dFRfg00I6BFJ9Atsjfs8mlg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", + "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.5.tgz", - "integrity": "sha512-iQiEMt8Q4/5aRGHpGVK2Zc7a6mx7qEAO7qehgSug3SDImnuMzgmm/wtJALXaz25zUj1PmnNHtShjFgk4PDx4nw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", + "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.5.tgz", - "integrity": "sha512-81tijpDg2a6I1Yhj4aWY1l3O1J4Cg/Pd7LfvuaH2VVInAkXtzibz9+zSPdUM1WvuUi128ksstAP0hM5w48vQgg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", + "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.5.tgz", - "integrity": "sha512-12rba2HwemQPa7BLIKCzm1pT2/RuQHtSFHdNl41cFiC6oi4tcrp7gjB07pxQvFpcADojQywSjblQth6gJyE6CA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", + "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-for-of": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.5.tgz", - "integrity": "sha512-+DpCAJFPAvViR17PIMi9x2AE34dll5wNlXO43wagAX2YcRGgEVHCNFC4azG85b4YyyFarvkc/iD5NPrz4Oneqw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", + "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-function-name": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.5.tgz", - "integrity": "sha512-Fuec/KPSpVLbGo6z1RPw4EE1X+z9gZk1uQmnYy7v4xr4TO9p41v1AoUuXEtyqAI7H+xNJYSICzRqZBhDEkd3kQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", + "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", "requires": { - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.5.tgz", - "integrity": "sha512-B1j9C/IfvshnPcklsc93AVLTrNVa69iSqztylZH6qnmiAsDDOmmjEYqOm3Ts2lGSgTSywnBNiqC949VdD0/gfw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", + "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.5.tgz", - "integrity": "sha512-d57i3vPHWgIde/9Y8W/xSFUndhvhZN5Wu2TjRrN1MVz5KzdUihKnfDVlfP1U7mS5DNj/WHHhaE4/tTi4hIyHwQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", + "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.5.tgz", - "integrity": "sha512-oHI15S/hdJuSCfnwIz+4lm6wu/wBn7oJ8+QrkzPPwSFGXk8kgdI/AIKcbR/XnD1nQVMg/i6eNaXpszbGuwYDRQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", + "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", "requires": { - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.5.tgz", - "integrity": "sha512-ABhUkxvoQyqhCWyb8xXtfwqNMJD7tx+irIRnUh6lmyFud7Jln1WzONXKlax1fg/ey178EXbs4bSGNd6PngO+SQ==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", + "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", "requires": { - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-simple-access": "^7.16.0", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.5.tgz", - "integrity": "sha512-53gmLdScNN28XpjEVIm7LbWnD/b/TpbwKbLk6KV4KqC9WyU6rq1jnNmVG6UgAdQZVVGZVoik3DqHNxk4/EvrjA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", + "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", "requires": { - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.5.tgz", - "integrity": "sha512-qTFnpxHMoenNHkS3VoWRdwrcJ3FhX567GvDA3hRZKF0Dj8Fmg0UzySZp3AP2mShl/bzcywb/UWAMQIjA1bhXvw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", + "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", "requires": { - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.5.tgz", - "integrity": "sha512-/wqGDgvFUeKELW6ex6QB7dLVRkd5ehjw34tpXu1nhKC0sFfmaLabIswnpf8JgDyV2NeDmZiwoOb0rAmxciNfjA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", + "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0" + "@babel/helper-create-regexp-features-plugin": "^7.16.7" } }, "@babel/plugin-transform-new-target": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.5.tgz", - "integrity": "sha512-ZaIrnXF08ZC8jnKR4/5g7YakGVL6go6V9ql6Jl3ecO8PQaQqFE74CuM384kezju7Z9nGCCA20BqZaR1tJ/WvHg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", + "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-object-super": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.5.tgz", - "integrity": "sha512-tded+yZEXuxt9Jdtkc1RraW1zMF/GalVxaVVxh41IYwirdRgyAxxxCKZ9XB7LxZqmsjfjALxupNE1MIz9KH+Zg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", + "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/helper-replace-supers": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-replace-supers": "^7.16.7" } }, "@babel/plugin-transform-parameters": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.5.tgz", - "integrity": "sha512-B3O6AL5oPop1jAVg8CV+haeUte9oFuY85zu0jwnRNZZi3tVAbJriu5tag/oaO2kGaQM/7q7aGPBlTI5/sr9enA==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", + "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-property-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.5.tgz", - "integrity": "sha512-+IRcVW71VdF9pEH/2R/Apab4a19LVvdVsr/gEeotH00vSDVlKD+XgfSIw+cgGWsjDB/ziqGv/pGoQZBIiQVXHg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", + "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-react-display-name": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.5.tgz", - "integrity": "sha512-dHYCOnzSsXFz8UcdNQIHGvg94qPL/teF7CCiCEMRxmA1G2p5Mq4JnKVowCDxYfiQ9D7RstaAp9kwaSI+sXbnhw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", + "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-react-jsx": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.5.tgz", - "integrity": "sha512-+arLIz1d7kmwX0fKxTxbnoeG85ONSnLpvdODa4P3pc1sS7CV1hfmtYWufkW/oYsPnkDrEeQFxhUWcFnrXW7jQQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", + "integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-module-imports": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5", - "@babel/plugin-syntax-jsx": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/plugin-transform-react-jsx-development": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.5.tgz", - "integrity": "sha512-uQSLacMZSGLCxOw20dzo1dmLlKkd+DsayoV54q3MHXhbqgPzoiGerZQgNPl/Ro8/OcXV2ugfnkx+rxdS0sN5Uw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", + "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.5" + "@babel/plugin-transform-react-jsx": "^7.16.7" } }, "@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.5.tgz", - "integrity": "sha512-0nYU30hCxnCVCbRjSy9ahlhWZ2Sn6khbY4FqR91W+2RbSqkWEbVu2gXh45EqNy4Bq7sRU+H4i0/6YKwOSzh16A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", + "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", "requires": { - "@babel/helper-annotate-as-pure": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-annotate-as-pure": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-regenerator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.5.tgz", - "integrity": "sha512-2z+it2eVWU8TtQQRauvGUqZwLy4+7rTfo6wO4npr+fvvN1SW30ZF3O/ZRCNmTuu4F5MIP8OJhXAhRV5QMJOuYg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", + "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.5.tgz", - "integrity": "sha512-aIB16u8lNcf7drkhXJRoggOxSTUAuihTSTfAcpynowGJOZiGf+Yvi7RuTwFzVYSYPmWyARsPqUGoZWWWxLiknw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", + "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.5.tgz", - "integrity": "sha512-ZbuWVcY+MAXJuuW7qDoCwoxDUNClfZxoo7/4swVbOW1s/qYLOMHlm9YRWMsxMFuLs44eXsv4op1vAaBaBaDMVg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", + "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-spread": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.5.tgz", - "integrity": "sha512-5d6l/cnG7Lw4tGHEoga4xSkYp1euP7LAtrah1h1PgJ3JY7yNsjybsxQAnVK4JbtReZ/8z6ASVmd3QhYYKLaKZw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", + "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5", + "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.5.tgz", - "integrity": "sha512-usYsuO1ID2LXxzuUxifgWtJemP7wL2uZtyrTVM4PKqsmJycdS4U4mGovL5xXkfUheds10Dd2PjoQLXw6zCsCbg==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", + "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-template-literals": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.5.tgz", - "integrity": "sha512-gnyKy9RyFhkovex4BjKWL3BVYzUDG6zC0gba7VMLbQoDuqMfJ1SDXs8k/XK41Mmt1Hyp4qNAvGFb9hKzdCqBRQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", + "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.5.tgz", - "integrity": "sha512-ldxCkW180qbrvyCVDzAUZqB0TAeF8W/vGJoRcaf75awm6By+PxfJKvuqVAnq8N9wz5Xa6mSpM19OfVKKVmGHSQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", + "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.5.tgz", - "integrity": "sha512-shiCBHTIIChGLdyojsKQjoAyB8MBwat25lKM7MJjbe1hE0bgIppD+LX9afr41lLHOhqceqeWl4FkLp+Bgn9o1Q==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", + "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.5.tgz", - "integrity": "sha512-GTJ4IW012tiPEMMubd7sD07iU9O/LOo8Q/oU4xNhcaq0Xn8+6TcUQaHtC8YxySo1T+ErQ8RaWogIEeFhKGNPzw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", + "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.0", - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-create-regexp-features-plugin": "^7.16.7", + "@babel/helper-plugin-utils": "^7.16.7" } }, "@babel/preset-env": { @@ -13584,68 +13577,68 @@ } }, "@babel/register": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.5.tgz", - "integrity": "sha512-NpluD+cToBiZiDsG3y9rtIcqDyivsahpaM9csfyfiq1qQWduSmihUZ+ruIqqSDGjZKZMJfgAElo9x2YWlOQuRw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.17.0.tgz", + "integrity": "sha512-UNZsMAZ7uKoGHo1HlEXfteEOYssf64n/PNLHGqOKq/bgYcu/4LrQWAHJwSCb3BRZK8Hi5gkJdRcwrGTO2wtRCg==", "requires": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", "make-dir": "^2.1.0", - "pirates": "^4.0.0", + "pirates": "^4.0.5", "source-map-support": "^0.5.16" } }, "@babel/runtime": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.5.tgz", - "integrity": "sha512-TXWihFIS3Pyv5hzR7j6ihmeLkZfrXGxAr5UfSl8CHf+6q/wpiYDkUau0czckpYG8QmnCIuPpdLtuA9VmuGGyMA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", + "integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.5.tgz", - "integrity": "sha512-F1pMwvTiUNSAM8mc45kccMQxj31x3y3P+tA/X8hKNWp3/hUsxdGxZ3D3H8JIkxtfA8qGkaBTKvcmvStaYseAFw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.0.tgz", + "integrity": "sha512-qeydncU80ravKzovVncW3EYaC1ji3GpntdPgNcJy9g7hHSY6KX+ne1cbV3ov7Zzm4F1z0+QreZPCuw1ynkmYNg==", "dev": true, "requires": { - "core-js-pure": "^3.19.0", + "core-js-pure": "^3.20.2", "regenerator-runtime": "^0.13.4" } }, "@babel/template": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.0.tgz", - "integrity": "sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/parser": "^7.16.0", - "@babel/types": "^7.16.0" + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" } }, "@babel/traverse": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz", - "integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", + "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-environment-visitor": "^7.16.5", - "@babel/helper-function-name": "^7.16.0", - "@babel/helper-hoist-variables": "^7.16.0", - "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.5", - "@babel/types": "^7.16.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.17.0", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.17.0", + "@babel/types": "^7.17.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, @@ -13660,40 +13653,40 @@ } }, "@date-io/core": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.11.0.tgz", - "integrity": "sha512-DvPBnNoeuLaoSJZaxgpu54qzRhRKjSYVyQjhznTFrllKuDpm0sDFjHo6lvNLCM/cfMx2gb2PM2zY2kc9C8nmuw==" + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/core/-/core-2.13.1.tgz", + "integrity": "sha512-pVI9nfkf2qClb2Cxdq0Q4zJhdawMG4ybWZUVGifT78FDwzRMX2SwXBb55s5NRJk0HcIicDuxktmCtemZqMH1Zg==" }, "@date-io/date-fns": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.11.0.tgz", - "integrity": "sha512-mPQ71plBeFrArvBSHtjWMHXA89IUbZ6kuo2dsjlRC/1uNOybo91spIb+wTu03NxKTl8ut07s0jJ9svF71afpRg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/date-fns/-/date-fns-2.13.1.tgz", + "integrity": "sha512-8fmfwjiLMpFLD+t4NBwDx0eblWnNcgt4NgfT/uiiQTGI81fnPu9tpBMYdAcuWxaV7LLpXgzLBx1SYWAMDVUDQQ==", "requires": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" } }, "@date-io/dayjs": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.11.0.tgz", - "integrity": "sha512-w67vRK56NZJIKhJM/CrNbfnIcuMvR3ApfxzNZiCZ5w29sxgBDeKuX4M+P7A9r5HXOMGcsOcpgaoTDINNGkdpGQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/dayjs/-/dayjs-2.13.1.tgz", + "integrity": "sha512-5bL4WWWmlI4uGZVScANhHJV7Mjp93ec2gNeUHDqqLaMZhp51S0NgD25oqj/k0LqBn1cdU2MvzNpk/ObMmVv5cQ==", "requires": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" } }, "@date-io/luxon": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.11.1.tgz", - "integrity": "sha512-JUXo01kdPQxLORxqdENrgdUhooKgDUggsNRSdi2BcUhASIY2KGwwWXu8ikVHHGkw+DUF4FOEKGfkQd0RHSvX6g==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/luxon/-/luxon-2.13.1.tgz", + "integrity": "sha512-yG+uM7lXfwLyKKEwjvP8oZ7qblpmfl9gxQYae55ifbwiTs0CoCTkYkxEaQHGkYtTqGTzLqcb0O9Pzx6vgWg+yg==", "requires": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" } }, "@date-io/moment": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.11.0.tgz", - "integrity": "sha512-QSL+83qezQ9Ty0dtFgAkk6eC0GMl/lgYfDajeVUDB3zVA2A038hzczRLBg29ifnBGhQMPABxuOafgWwhDjlarg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@date-io/moment/-/moment-2.13.1.tgz", + "integrity": "sha512-XX1X/Tlvl3TdqQy2j0ZUtEJV6Rl8tOyc5WOS3ki52He28Uzme4Ro/JuPWTMBDH63weSWIZDlbR7zBgp3ZA2y1A==", "requires": { - "@date-io/core": "^2.11.0" + "@date-io/core": "^2.13.1" } }, "@discoveryjs/json-ext": { @@ -13702,9 +13695,9 @@ "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==" }, "@emotion/babel-plugin": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.1.tgz", - "integrity": "sha512-K3/6Y+J/sIAjplf3uIteWLhPuOyuMNnE+iyYnTF/m294vc6IL90kTHp7y8ldZYbpKlP17rpOWDKM9DvTcrOmNQ==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz", + "integrity": "sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==", "requires": { "@babel/helper-module-imports": "^7.12.13", "@babel/plugin-syntax-jsx": "^7.12.13", @@ -13817,6 +13810,14 @@ "comment-parser": "1.2.4", "esquery": "^1.4.0", "jsdoc-type-pratt-parser": "2.0.0" + }, + "dependencies": { + "jsdoc-type-pratt-parser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.0.0.tgz", + "integrity": "sha512-sUuj2j48wxrEpbFjDp1sAesAxPiLT+z0SWVmMafyIINs6Lj5gIPKh3VrkBZu4E/Dv+wHpOot0m6H8zlHQjwqeQ==", + "dev": true + } } }, "@eslint/eslintrc": { @@ -13837,9 +13838,9 @@ }, "dependencies": { "globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -13847,19 +13848,6 @@ } } }, - "@hookform/devtools": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@hookform/devtools/-/devtools-4.0.1.tgz", - "integrity": "sha512-xVPIK8FGi3Fp7q9qxWrXLwiGxoZzn6g2ihIBQG0ddpiVSAAsH21Jh39tyyYWtkHZkTo9deiPs98SwXnN48hMjg==", - "requires": { - "@emotion/react": "^11.1.5", - "@emotion/styled": "^11.3.0", - "@types/lodash": "^4.14.168", - "little-state-machine": "^4.1.0", - "lodash": "^4.17.21", - "react-simple-animate": "^3.3.12" - } - }, "@hookform/resolvers": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.2.tgz", @@ -13990,15 +13978,15 @@ }, "dependencies": { "@mui/system": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.2.4.tgz", - "integrity": "sha512-08WrDLzmY0/ag5wSzT0Qf2DkuPHdqkWbDUOIVs0VIkaq8tRH+EtnnLxuqyf8WLcytJZIcKcoLQDLWqbFivZ9lA==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.4.0.tgz", + "integrity": "sha512-LX7g5gK5yCwiueSUVG73uVNc0yeHjsWUIFLrnPjP3m+J7O38RkPqyao5nZahhaSL1PGNbR9+zfkxljXthO9QqA==", "requires": { - "@babel/runtime": "^7.16.3", - "@mui/private-theming": "^5.2.3", - "@mui/styled-engine": "^5.2.4", + "@babel/runtime": "^7.16.7", + "@mui/private-theming": "^5.3.0", + "@mui/styled-engine": "^5.3.0", "@mui/types": "^7.1.0", - "@mui/utils": "^5.2.3", + "@mui/utils": "^5.3.0", "clsx": "^1.1.1", "csstype": "^3.0.10", "prop-types": "^15.7.2" @@ -14060,22 +14048,22 @@ } }, "@mui/private-theming": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.2.3.tgz", - "integrity": "sha512-Lc1Cmu8lSsYZiXADi9PBb17Ho82ZbseHQujUFAcp6bCJ5x/d+87JYCIpCBMagPu/isRlFCwbziuXPmz7WOzJPQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.3.0.tgz", + "integrity": "sha512-EBobUEyM9fMnteKrVPp8pTMUh81xXakyfdpkoh7Y19q9JpD2eh7QGAQVJVj0JBFlcUJD60NIE4K8rdokrRmLwg==", "requires": { - "@babel/runtime": "^7.16.3", - "@mui/utils": "^5.2.3", + "@babel/runtime": "^7.16.7", + "@mui/utils": "^5.3.0", "prop-types": "^15.7.2" } }, "@mui/styled-engine": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.2.4.tgz", - "integrity": "sha512-tlilkVsAR+MeWIPILzj1uGjiy5tKONZgblXY49LECUNF7u7aTDszqmv0hRG+1IAZjNts+ox8XAlldPNfj+OKvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.3.0.tgz", + "integrity": "sha512-I4YemFy9WnCLUdZ5T+6egpzc8e7Jq/uh9AJ3QInZHbyNu/9I2SWvNn7vHjWOT/D8Y8LMzIOhu5WwZbzjez7YRw==", "requires": { - "@babel/runtime": "^7.16.3", - "@emotion/cache": "^11.6.0", + "@babel/runtime": "^7.16.7", + "@emotion/cache": "^11.7.1", "prop-types": "^15.7.2" } }, @@ -14125,11 +14113,11 @@ "requires": {} }, "@mui/utils": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.2.3.tgz", - "integrity": "sha512-sQujlajIS0zQKcGIS6tZR0L1R+ib26B6UtuEn+cZqwKHsPo3feuS+SkdscYBdcCdMbrZs4gj8WIJHl2z6tbSzQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.3.0.tgz", + "integrity": "sha512-O/E9IQKPMg0OrN7+gkn7Ga5o5WA2iXQGdyqNBFPNrYzxOvwzsEtM5K7MtTCGGYKFe8mhTRM0ZOjh5OM0dglw+Q==", "requires": { - "@babel/runtime": "^7.16.3", + "@babel/runtime": "^7.16.7", "@types/prop-types": "^15.7.4", "@types/react-is": "^16.7.1 || ^17.0.0", "prop-types": "^15.7.2", @@ -14198,9 +14186,9 @@ } }, "@popperjs/core": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.0.tgz", - "integrity": "sha512-zrsUxjLOKAzdewIDRWy9nsV1GQsKBCWaGwsZQlCgr6/q+vjyZhFgqedLfFBuI9anTPEUT4APq9Mu0SZBTzIcGQ==" + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz", + "integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==" }, "@reach/observe-rect": { "version": "1.2.0", @@ -14360,9 +14348,9 @@ "integrity": "sha512-T4aL2ZzaILkLGKbxssipYVRs8334PSR9FQzTGftZbc3jIPGkiXXS7qUCh8/q8UWFzxBZQ92dvR0v7+AM9wL2PA==" }, "@types/d3-ease": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-2.0.1.tgz", - "integrity": "sha512-Af1ftZXv82ktPCk1+Vxe7f+VSfxDsQ1mwwakDl17+UzI/ii3vsDIAzaBDDSEQd2Cg9BYPTSx8wXH8rJNDuSjeg==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-2.0.2.tgz", + "integrity": "sha512-29Y73Tg6o6aL+3/S/kEun84m5BO4bjRNau6pMWv9N9rZHcJv/O/07mW6EjqxrePZZS64fj0wiB5LMHr4Jzf3eQ==" }, "@types/d3-fetch": { "version": "2.0.2", @@ -14482,18 +14470,18 @@ } }, "@types/eslint": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz", - "integrity": "sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", "requires": { "@types/estree": "*", "@types/json-schema": "*" } }, "@types/eslint-scope": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.2.tgz", - "integrity": "sha512-TzgYCWoPiTeRg6RQYgtuW7iODtVoKu3RVL72k3WohqhjfaOLK5Mg2T4Tg1o2bSfu0vPkoI48wdQFv5b/Xe04wQ==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "requires": { "@types/eslint": "*", "@types/estree": "*" @@ -14543,9 +14531,9 @@ "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==" }, "@types/node": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", - "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==" + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", + "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" }, "@types/parse-json": { "version": "4.0.0", @@ -14558,9 +14546,9 @@ "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" }, "@types/react": { - "version": "17.0.37", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.37.tgz", - "integrity": "sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==", + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", + "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -14576,9 +14564,9 @@ } }, "@types/react-redux": { - "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz", - "integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==", + "version": "7.1.22", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", + "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -14731,23 +14719,23 @@ } }, "@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "requires": {} }, "@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "requires": { "envinfo": "^7.7.3" } }, "@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "requires": {} }, "@xtuc/ieee754": { @@ -14761,12 +14749,12 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "acorn": { @@ -15028,9 +15016,9 @@ "dev": true }, "async": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", - "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "asynckit": { "version": "0.4.0", @@ -15058,9 +15046,9 @@ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "axe-core": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz", - "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.1.tgz", + "integrity": "sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==", "dev": true }, "axios": { @@ -15520,9 +15508,9 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" }, "caniuse-lite": { - "version": "1.0.30001287", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001287.tgz", - "integrity": "sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==" + "version": "1.0.30001307", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001307.tgz", + "integrity": "sha512-+MXEMczJ4FuxJAUp0jvAl6Df0NI/OfW1RWEE61eSmzS7hw6lz4IKutbhbXendwq8BljfFuHtu26VWsg4afQ7Ng==" }, "caseless": { "version": "0.12.0", @@ -15547,9 +15535,9 @@ } }, "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "optional": true, "requires": { "anymatch": "~3.1.2", @@ -15857,9 +15845,9 @@ "integrity": "sha512-vJlUi/7YdlCZeL6fXvWNaLUPh/id12WXj3MbkMw5uOyF0PfWPBNOCNbs53YqgrvtujLNlt9JQpruyIKkUZ+PKA==" }, "core-js-compat": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.0.tgz", - "integrity": "sha512-relrah5h+sslXssTTOkvqcC/6RURifB0W5yhYBdBkaPYa5/2KBMiog3XiD+s3TwEHWxInWVv4Jx2/Lw0vng+IQ==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", + "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", "requires": { "browserslist": "^4.19.1", "semver": "7.0.0" @@ -15873,9 +15861,9 @@ } }, "core-js-pure": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.20.0.tgz", - "integrity": "sha512-qsrbIwWSEEYOM7z616jAVgwhuDDtPLwZSpUsU3vyUkHYqKTf/uwOJBZg2V7lMurYWkpVlaVOxBrfX0Q3ppvjfg==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.0.tgz", + "integrity": "sha512-VaJUunCZLnxuDbo1rNOzwbet9E1K9joiXS5+DQMPtgxd24wfsZbJZMMfQLGYMlCUvSxLfsRUUhoOR2x28mFfeg==", "dev": true }, "core-util-is": { @@ -16115,9 +16103,9 @@ } }, "damerau-levenshtein": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz", - "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, "dashdash": { @@ -16301,9 +16289,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.4.23", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.23.tgz", - "integrity": "sha512-q3tB59Api3+DMbLnDPkW/UBHBO7KTGcF+rDCeb0GAGyqFj562s6y+c/2tDKTS/y5lbC+JOvT4MSUALJLPqlcSA==" + "version": "1.4.65", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.65.tgz", + "integrity": "sha512-0/d8Skk8sW3FxXP0Dd6MnBlrwx7Qo9cqQec3BlIAlvKnrmS3pHsIbaroEi+nd0kZkGpQ6apMEre7xndzjlEnLw==" }, "elliptic": { "version": "6.5.4", @@ -16375,9 +16363,9 @@ }, "dependencies": { "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" }, "ws": { "version": "8.2.3", @@ -16610,9 +16598,9 @@ "dev": true }, "globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", + "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -16680,6 +16668,51 @@ "@babel/plugin-transform-react-jsx-development": "^7.14.5", "@babel/plugin-transform-react-pure-annotations": "^7.14.5" } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint-plugin-import": { + "version": "2.25.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", + "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.1", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, @@ -16767,14 +16800,13 @@ } }, "eslint-module-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", - "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", "dev": true, "requires": { "debug": "^3.2.7", - "find-up": "^2.1.0", - "pkg-dir": "^2.0.0" + "find-up": "^2.1.0" }, "dependencies": { "debug": { @@ -16852,24 +16884,25 @@ "requires": {} }, "eslint-plugin-import": { - "version": "2.25.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", - "integrity": "sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg==", + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", + "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", "dev": true, + "peer": true, "requires": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.1", + "eslint-module-utils": "^2.7.2", "has": "^1.0.3", "is-core-module": "^2.8.0", "is-glob": "^4.0.3", "minimatch": "^3.0.4", "object.values": "^1.1.5", "resolve": "^1.20.0", - "tsconfig-paths": "^3.11.0" + "tsconfig-paths": "^3.12.0" }, "dependencies": { "debug": { @@ -16877,6 +16910,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "peer": true, "requires": { "ms": "2.0.0" } @@ -16886,6 +16920,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "peer": true, "requires": { "esutils": "^2.0.2" } @@ -16894,7 +16929,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "dev": true, + "peer": true } } }, @@ -16961,9 +16997,9 @@ }, "dependencies": { "ignore": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true } } @@ -17249,9 +17285,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -17364,54 +17400,6 @@ "commondir": "^1.0.1", "make-dir": "^2.0.0", "pkg-dir": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "requires": { - "find-up": "^3.0.0" - } - } } }, "find-root": { @@ -17448,9 +17436,9 @@ } }, "flatted": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", - "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, "fn.name": { @@ -17669,22 +17657,22 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "dependencies": { "ignore": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "slash": { "version": "3.0.0", @@ -17694,9 +17682,9 @@ } }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, "graphlib": { "version": "2.1.8", @@ -17961,9 +17949,9 @@ "dev": true }, "immer": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz", - "integrity": "sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA==" + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", + "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==" }, "immutable": { "version": "4.0.0-rc.12", @@ -17980,9 +17968,9 @@ } }, "import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "requires": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -18129,9 +18117,9 @@ "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "requires": { "has": "^1.0.3" } @@ -18262,9 +18250,9 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.0.tgz", + "integrity": "sha512-8OEHiPNOPTfaWnJ2SUHM8fmgeGq37uuGsQBvGKQJl1f+6WIy6g7G3fE2ruI5294bUKUI9FaCWt5hDvO8HSwsSg==", "requires": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -18307,9 +18295,9 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdoc-type-pratt-parser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.0.0.tgz", - "integrity": "sha512-sUuj2j48wxrEpbFjDp1sAesAxPiLT+z0SWVmMafyIINs6Lj5gIPKh3VrkBZu4E/Dv+wHpOot0m6H8zlHQjwqeQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-2.2.2.tgz", + "integrity": "sha512-zRokSWcPLSWkoNzsWn9pq7YYSwDhKyEe+cJYT2qaPqLOOJb5sFSi46BPj81vP+e8chvCNdQL9RG86Bi9EI6MDw==", "dev": true }, "jsesc": { @@ -18564,12 +18552,6 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, - "little-state-machine": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/little-state-machine/-/little-state-machine-4.2.0.tgz", - "integrity": "sha512-UMWelGx2fJfUC3KGy2FajC+H6+DJ9nCHJeolm4pq0Qldks+MemC6/6PTIhRqDpaBkna2TMG4bewidrt393cSsw==", - "requires": {} - }, "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -18675,11 +18657,11 @@ "dev": true }, "logform": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", - "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.2.tgz", + "integrity": "sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA==", "requires": { - "colors": "^1.2.1", + "colors": "1.4.0", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^1.1.0", @@ -18745,9 +18727,9 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "memfs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.0.tgz", - "integrity": "sha512-o/RfP0J1d03YwsAxyHxAYs2kyJp55AFkMazlFAZFR2I2IXkxiUTXRabJ6RmNNCQ83LAD2jy52Khj0m3OffpNdA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", + "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", "dev": true, "requires": { "fs-monkey": "1.0.3" @@ -18949,9 +18931,9 @@ "integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==" }, "nanoid": { - "version": "3.1.30", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz", - "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==" + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" }, "napi-build-utils": { "version": "1.0.2", @@ -18983,9 +18965,9 @@ } }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "neo-async": { "version": "2.6.2", @@ -19150,9 +19132,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==" + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" }, "object-keys": { "version": "1.1.1", @@ -19483,9 +19465,9 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pify": { "version": "4.0.1", @@ -19493,55 +19475,55 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" }, "pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==" + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==" }, "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "requires": { - "find-up": "^2.1.0" + "find-up": "^3.0.0" }, "dependencies": { "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "^2.0.0" + "locate-path": "^3.0.0" } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" } } }, @@ -19599,13 +19581,13 @@ "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==" }, "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", + "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", "requires": { - "nanoid": "^3.1.30", + "nanoid": "^3.2.0", "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "source-map-js": "^1.0.2" } }, "postcss-modules-extract-imports": { @@ -19641,9 +19623,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.7.tgz", - "integrity": "sha512-U+b/Deoi4I/UmE6KOVPpnhS7I7AYdKbhGcat+qTQ27gycvaACvNEw11ba6RrkwVmDVRW7sigWgLj4/KbbJjeDA==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -19724,9 +19706,9 @@ } }, "property-expr": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", - "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", + "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==" }, "proxy-addr": { "version": "2.0.7", @@ -20176,12 +20158,6 @@ "tiny-warning": "^1.0.0" } }, - "react-simple-animate": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/react-simple-animate/-/react-simple-animate-3.3.12.tgz", - "integrity": "sha512-lFXjxD6ficcpOMsHfcDs1jqdkCve6jNlJnubOCzVOLswFDRANsaLN4KwpezDuliEFz8Q1zyj4J7Tmj3KMRnPcg==", - "requires": {} - }, "react-table": { "version": "7.7.0", "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.7.0.tgz", @@ -20266,9 +20242,9 @@ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" }, "regenerate-unicode-properties": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", - "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", + "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", "requires": { "regenerate": "^1.4.2" } @@ -20287,9 +20263,9 @@ } }, "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", + "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -20303,14 +20279,14 @@ "dev": true }, "regexpu-core": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", - "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", + "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", "requires": { "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^9.0.0", - "regjsgen": "^0.5.2", - "regjsparser": "^0.7.0", + "regenerate-unicode-properties": "^10.0.1", + "regjsgen": "^0.6.0", + "regjsparser": "^0.8.2", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.0.0" } @@ -20322,14 +20298,14 @@ "dev": true }, "regjsgen": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", - "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", + "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" }, "regjsparser": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", - "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", + "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", "requires": { "jsesc": "~0.5.0" }, @@ -20369,9 +20345,9 @@ }, "dependencies": { "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" }, "uuid": { "version": "3.4.0", @@ -20407,12 +20383,13 @@ "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-cwd": { @@ -20645,9 +20622,9 @@ } }, "signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "simple-concat": { "version": "1.0.1", @@ -20655,9 +20632,9 @@ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" }, "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", "requires": { "decompress-response": "^4.2.0", "once": "^1.3.1", @@ -20784,9 +20761,9 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, "source-map-support": { "version": "0.5.21", @@ -20840,9 +20817,9 @@ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -21061,10 +21038,15 @@ "has-flag": "^3.0.0" } }, + "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==" + }, "table": { - "version": "6.7.5", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.5.tgz", - "integrity": "sha512-LFNeryOqiQHqCVKzhkymKwt6ozeRhlm8IL1mE8rNUurkir4heF6PzMyRgaTa4tlyPTGGgXuvVOF/OLWiH09Lqw==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", "dev": true, "requires": { "ajv": "^8.0.1", @@ -21075,9 +21057,9 @@ }, "dependencies": { "ajv": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", - "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", + "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -21149,9 +21131,9 @@ }, "dependencies": { "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "optional": true, "peer": true }, @@ -21567,9 +21549,9 @@ }, "dependencies": { "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==" + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" }, "enhanced-resolve": { "version": "5.8.3", @@ -21759,13 +21741,13 @@ } }, "winston-transport": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz", - "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", "requires": { - "logform": "^2.2.0", - "readable-stream": "^3.4.0", - "triple-beam": "^1.2.0" + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" }, "dependencies": { "readable-stream": { diff --git a/src/fireedge/package.json b/src/fireedge/package.json index 62b0d0974a..493f801f2d 100644 --- a/src/fireedge/package.json +++ b/src/fireedge/package.json @@ -54,7 +54,6 @@ "@babel/preset-react": "7.16.0", "@emotion/react": "11.6.0", "@emotion/styled": "11.6.0", - "@hookform/devtools": "4.0.1", "@hookform/resolvers": "2.8.2", "@loadable/babel-plugin": "5.13.2", "@loadable/component": "5.15.0", diff --git a/src/fireedge/src/client/apps/provision/_app.js b/src/fireedge/src/client/apps/provision/_app.js index 661be5b175..bd5f20e550 100644 --- a/src/fireedge/src/client/apps/provision/_app.js +++ b/src/fireedge/src/client/apps/provision/_app.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useEffect, useMemo, JSXElementConstructor } from 'react' +import { useEffect, useMemo, ReactElement } from 'react' import Router from 'client/router' import { ENDPOINTS, PATH } from 'client/apps/provision/routes' @@ -21,7 +21,9 @@ import { ENDPOINTS as DEV_ENDPOINTS } from 'client/router/dev' import { useGeneral, useGeneralApi } from 'client/features/General' import { useAuth, useAuthApi } from 'client/features/Auth' -import { useProvisionTemplate, useProvisionApi } from 'client/features/One' +import provisionApi from 'client/features/OneApi/provision' +import providerApi from 'client/features/OneApi/provider' +import { useSocket } from 'client/hooks' import Sidebar from 'client/components/Sidebar' import Notifier from 'client/components/Notifier' @@ -31,37 +33,54 @@ import { _APPS } from 'client/constants' export const APP_NAME = _APPS.provision.name +const MESSAGE_PROVISION_SUCCESS_CREATED = 'Provision successfully created' + /** * Provision App component. * - * @returns {JSXElementConstructor} App rendered. + * @returns {ReactElement} App rendered. */ const ProvisionApp = () => { - const { isLogged, jwt, firstRender, providerConfig } = useAuth() - const { getAuthUser, logout, getProviderConfig } = useAuthApi() + const { getProvisionSocket } = useSocket() + const { isLogged, jwt, firstRender } = useAuth() + const { getAuthUser, logout } = useAuthApi() - const provisionTemplate = useProvisionTemplate() - const { getProvisionsTemplates } = useProvisionApi() + const { appTitle, zone } = useGeneral() + const { changeAppTitle, enqueueSuccess } = useGeneralApi() - const { appTitle } = useGeneral() - const { changeAppTitle } = useGeneralApi() + const queryProps = [undefined, { skip: !jwt }] + provisionApi.endpoints.getProvisionTemplates.useQuery(...queryProps) + providerApi.endpoints.getProviderConfig.useQuery(...queryProps) useEffect(() => { ;(async () => { appTitle !== APP_NAME && changeAppTitle(APP_NAME) try { - if (jwt) { - getAuthUser() - !providerConfig && (await getProviderConfig()) - !provisionTemplate?.length && (await getProvisionsTemplates()) - } + jwt && getAuthUser() } catch { logout() } })() }, [jwt]) + useEffect(() => { + if (!jwt || !zone) return + + const socket = getProvisionSocket((payload) => { + const { command, data } = payload + + // Dispatch successfully notification when one provision is created + if (command === 'create' && data === MESSAGE_PROVISION_SUCCESS_CREATED) { + enqueueSuccess(MESSAGE_PROVISION_SUCCESS_CREATED) + } + }) + + socket?.on() + + return () => socket?.off() + }, [jwt, zone]) + const endpoints = useMemo( () => [...ENDPOINTS, ...(isDevelopment() ? DEV_ENDPOINTS : [])], [] diff --git a/src/fireedge/src/client/apps/provision/index.js b/src/fireedge/src/client/apps/provision/index.js index cca823f7c5..b89b1727d2 100644 --- a/src/fireedge/src/client/apps/provision/index.js +++ b/src/fireedge/src/client/apps/provision/index.js @@ -21,7 +21,6 @@ import { StaticRouter, BrowserRouter } from 'react-router-dom' import { Provider as ReduxProvider } from 'react-redux' import { Store } from 'redux' -import SocketProvider from 'client/providers/socketProvider' import MuiProvider from 'client/providers/muiProvider' import NotistackProvider from 'client/providers/notistackProvider' import { TranslateProvider } from 'client/components/HOC' @@ -42,25 +41,23 @@ buildTranslationLocale() */ const Provision = ({ store = {}, location = '', context = {} }) => ( - - - - - {location && context ? ( - // server build - - - - ) : ( - // browser build - - - - )} - - - - + + + + {location && context ? ( + // server build + + + + ) : ( + // browser build + + + + )} + + + ) diff --git a/src/fireedge/src/client/apps/sunstone/_app.js b/src/fireedge/src/client/apps/sunstone/_app.js index 395ed81da7..6bea61cc29 100644 --- a/src/fireedge/src/client/apps/sunstone/_app.js +++ b/src/fireedge/src/client/apps/sunstone/_app.js @@ -26,7 +26,7 @@ import { ENDPOINTS as DEV_ENDPOINTS } from 'client/router/dev' import { useGeneral, useGeneralApi } from 'client/features/General' import { useAuth, useAuthApi } from 'client/features/Auth' -import { useSystem, useSystemApi } from 'client/features/One' +import systemApi from 'client/features/OneApi/system' import Sidebar from 'client/components/Sidebar' import Notifier from 'client/components/Notifier' @@ -42,26 +42,23 @@ export const APP_NAME = _APPS.sunstone.name * @returns {JSXElementConstructor} App rendered. */ const SunstoneApp = () => { - const { isLogged, jwt, firstRender, view, views, config } = useAuth() - const { getAuthUser, logout, getSunstoneViews, getSunstoneConfig } = - useAuthApi() + const { isLogged, jwt, firstRender, view } = useAuth() + const { getAuthUser, logout } = useAuthApi() const { appTitle } = useGeneral() const { changeAppTitle } = useGeneralApi() - const { config: oneConfig } = useSystem() - const { getOneConfig } = useSystemApi() + + const queryProps = [undefined, { skip: !jwt }] + systemApi.endpoints.getOneConfig.useQuery(...queryProps) + systemApi.endpoints.getSunstoneConfig.useQuery(...queryProps) + const views = systemApi.endpoints.getSunstoneViews.useQuery(...queryProps) useEffect(() => { ;(async () => { appTitle !== APP_NAME && changeAppTitle(APP_NAME) try { - if (jwt) { - getAuthUser() - !view && (await getSunstoneViews()) - !config && (await getSunstoneConfig()) - !oneConfig && getOneConfig() - } + jwt && getAuthUser() } catch { logout() } @@ -71,7 +68,7 @@ const SunstoneApp = () => { const endpoints = useMemo( () => [ ...ENDPOINTS, - ...(view ? getEndpointsByView(views?.[view], ONE_ENDPOINTS) : []), + ...(view ? getEndpointsByView(views?.data?.[view], ONE_ENDPOINTS) : []), ...(isDevelopment() ? DEV_ENDPOINTS : []), ], [view] diff --git a/src/fireedge/src/server/routes/api/oneflow/basepath.js b/src/fireedge/src/client/components/Buttons/QueryButton.js similarity index 71% rename from src/fireedge/src/server/routes/api/oneflow/basepath.js rename to src/fireedge/src/client/components/Buttons/QueryButton.js index 968c1a9fd8..cb28612b2c 100644 --- a/src/fireedge/src/server/routes/api/oneflow/basepath.js +++ b/src/fireedge/src/client/components/Buttons/QueryButton.js @@ -13,11 +13,22 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +import { memo } from 'react' +import PropTypes from 'prop-types' -const SERVICE = 'service' -const SERVICE_TEMPLATE = 'service_template' +import { SubmitButton } from 'client/components/FormControl' -module.exports = { - SERVICE, - SERVICE_TEMPLATE, +const QueryButton = memo(({ useQuery, ...props }) => { + const { refetch, isFetching } = useQuery?.() ?? {} + + return +}) + +QueryButton.propTypes = { + useQuery: PropTypes.func, + ...SubmitButton.propTypes, } + +QueryButton.displayName = 'QueryButton' + +export default QueryButton diff --git a/src/fireedge/src/client/components/Buttons/ScheduleAction.js b/src/fireedge/src/client/components/Buttons/ScheduleAction.js index aa52fc39bf..b18ee4c8e3 100644 --- a/src/fireedge/src/client/components/Buttons/ScheduleAction.js +++ b/src/fireedge/src/client/components/Buttons/ScheduleAction.js @@ -18,7 +18,7 @@ import PropTypes from 'prop-types' import { Trash, Edit, ClockOutline } from 'iconoir-react' -import { useAuth } from 'client/features/Auth' +import { useGetSunstoneConfigQuery } from 'client/features/OneApi/system' import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm' import { CreateCharterForm, @@ -28,9 +28,13 @@ import { } from 'client/components/Forms/Vm' import { Tr, Translate } from 'client/components/HOC' -import { ScheduledAction } from 'client/models/Scheduler' import { sentenceCase } from 'client/utils' -import { T, VM_ACTIONS, VM_ACTIONS_IN_CHARTER } from 'client/constants' +import { + T, + VM_ACTIONS, + VM_ACTIONS_IN_CHARTER, + ScheduleAction, +} from 'client/constants' /** * Returns a button to trigger form to create a scheduled action. @@ -53,7 +57,7 @@ const CreateSchedButton = memo(({ vm, relative, onSubmit }) => ( { name: T.PunctualAction, dialogProps: { - title: T.ScheduledAction, + title: T.ScheduleAction, dataCy: 'modal-sched-actions', }, form: () => @@ -71,7 +75,7 @@ const CreateSchedButton = memo(({ vm, relative, onSubmit }) => ( * * @param {object} props - Props * @param {object} props.vm - Vm resource - * @param {ScheduledAction} props.schedule - Schedule action + * @param {ScheduleAction} props.schedule - Schedule action * @param {boolean} [props.relative] - Applies to the form relative format * @param {function():Promise} props.onSubmit - Submit function * @returns {ReactElement} Button @@ -91,10 +95,7 @@ const UpdateSchedButton = memo(({ vm, schedule, relative, onSubmit }) => { { dialogProps: { title: ( - + ), dataCy: 'modal-sched-actions', }, @@ -113,7 +114,7 @@ const UpdateSchedButton = memo(({ vm, schedule, relative, onSubmit }) => { * Returns a button to trigger modal to delete a scheduled action. * * @param {object} props - Props - * @param {ScheduledAction} props.schedule - Schedule action + * @param {ScheduleAction} props.schedule - Schedule action * @param {function():Promise} props.onSubmit - Submit function * @returns {ReactElement} Button */ @@ -156,7 +157,7 @@ const DeleteSchedButton = memo(({ onSubmit, schedule }) => { * @returns {ReactElement} Button */ const CharterButton = memo(({ relative, onSubmit }) => { - const { config } = useAuth() + const { data: config } = useGetSunstoneConfigQuery() const leases = useMemo( () => @@ -164,7 +165,7 @@ const CharterButton = memo(({ relative, onSubmit }) => { Object.entries(config?.leases ?? {}).filter(([action]) => VM_ACTIONS_IN_CHARTER.includes(action) ), - [config.leases] + [config?.leases] ) return ( @@ -178,7 +179,7 @@ const CharterButton = memo(({ relative, onSubmit }) => { options={[ { dialogProps: { - title: T.ScheduledAction, + title: T.ScheduleAction, dataCy: 'modal-sched-actions', }, form: () => diff --git a/src/fireedge/src/client/components/Cards/DatastoreCard.js b/src/fireedge/src/client/components/Cards/DatastoreCard.js index c9d727c374..054ebf9e68 100644 --- a/src/fireedge/src/client/components/Cards/DatastoreCard.js +++ b/src/fireedge/src/client/components/Cards/DatastoreCard.js @@ -13,106 +13,90 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo } from 'react' +import { memo, ReactElement } from 'react' import PropTypes from 'prop-types' import { Typography } from '@mui/material' -import makeStyles from '@mui/styles/makeStyles' -import { Folder as DatastoreIcon } from 'iconoir-react' +import { User, Group, Lock, Cloud, Server } from 'iconoir-react' -import SelectCard, { Action } from 'client/components/Cards/SelectCard' import { - StatusBadge, + StatusCircle, StatusChip, LinearProgressWithLabel, } from 'client/components/Status' -import * as DatastoreModel from 'client/models/Datastore' - -const useStyles = makeStyles({ - title: { - display: 'flex', - gap: '0.5rem', - }, - content: { - padding: '2em', - display: 'flex', - flexFlow: 'column', - gap: '1em', - }, -}) +import { getState, getType, getCapacityInfo } from 'client/models/Datastore' +import { rowStyles } from 'client/components/Tables/styles' +import { Datastore } from 'client/constants' const DatastoreCard = memo( - ({ value, isSelected, handleClick, actions }) => { - const classes = useStyles() + /** + * @param {object} props - Props + * @param {Datastore} props.datastore - Datastore resource + * @param {object} props.rootProps - Props to root component + * @param {ReactElement} props.actions - Actions + * @returns {ReactElement} - Card + */ + ({ datastore, rootProps, actions }) => { + const classes = rowStyles() - const { ID, NAME } = value + const { ID, NAME, UNAME, GNAME, CLUSTERS, LOCK, PROVISION_ID } = datastore - const type = DatastoreModel.getType(value) - const state = DatastoreModel.getState(value) - - const { percentOfUsed, percentLabel } = - DatastoreModel.getCapacityInfo(value) + const type = getType(datastore) + const { color: stateColor, name: stateName } = getState(datastore) + const { percentOfUsed, percentLabel } = getCapacityInfo(datastore) + const totalClusters = [CLUSTERS?.ID ?? []].flat().join(',') return ( - ( - - ))} - icon={ - - - - } - title={ - - - {NAME} - - - - } - subheader={`#${ID}`} - isSelected={isSelected} - handleClick={handleClick} - > -
+
+
+ +
+
+
+ {NAME} + + {LOCK && } + + +
+
+ {`#${ID}`} + + + {` ${UNAME}`} + + + + {` ${GNAME}`} + + {PROVISION_ID && ( + + + {` ${PROVISION_ID}`} + + )} + + + {` ${totalClusters}`} + +
+
+
- + {actions &&
{actions}
} +
) - }, - (prev, next) => - prev.isSelected === next.isSelected && - prev.value?.STATE === next.value?.STATE + } ) DatastoreCard.propTypes = { - value: PropTypes.shape({ - ID: PropTypes.string.isRequired, - NAME: PropTypes.string.isRequired, - TYPE: PropTypes.string, - STATE: PropTypes.string, - TOTAL_MB: PropTypes.string, - FREE_MB: PropTypes.string, - USED_MB: PropTypes.string, + datastore: PropTypes.object, + rootProps: PropTypes.shape({ + className: PropTypes.string, }), - isSelected: PropTypes.bool, - handleClick: PropTypes.func, - actions: PropTypes.arrayOf( - PropTypes.shape({ - handleClick: PropTypes.func.isRequired, - icon: PropTypes.node.isRequired, - cy: PropTypes.string, - }) - ), -} - -DatastoreCard.defaultProps = { - value: {}, - isSelected: false, - handleClick: undefined, - actions: undefined, + actions: PropTypes.any, } DatastoreCard.displayName = 'DatastoreCard' diff --git a/src/fireedge/src/client/components/Cards/DiskCard.js b/src/fireedge/src/client/components/Cards/DiskCard.js new file mode 100644 index 0000000000..8ca670318f --- /dev/null +++ b/src/fireedge/src/client/components/Cards/DiskCard.js @@ -0,0 +1,174 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo, useMemo } from 'react' +import PropTypes from 'prop-types' +import { DatabaseSettings, Folder, ModernTv } from 'iconoir-react' +import { Box, Typography, Paper } from '@mui/material' + +import DiskSnapshotCard from 'client/components/Cards/DiskSnapshotCard' +import { StatusChip } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' + +import { stringToBoolean } from 'client/models/Helper' +import { prettyBytes } from 'client/utils' +import { Disk } from 'client/constants' + +const DiskCard = memo( + ({ + disk = {}, + actions = [], + extraActionProps = {}, + snapshotActions = [], + extraSnapshotActionProps = {}, + }) => { + const classes = rowStyles() + + /** @type {Disk} */ + const { + DISK_ID, + DATASTORE, + TARGET, + IMAGE, + TYPE, + FORMAT, + SIZE, + MONITOR_SIZE, + READONLY, + PERSISTENT, + SAVE, + CLONE, + IS_CONTEXT, + SNAPSHOTS, + } = disk + + const size = +SIZE ? prettyBytes(+SIZE, 'MB') : '-' + const monitorSize = +MONITOR_SIZE ? prettyBytes(+MONITOR_SIZE, 'MB') : '-' + + const type = String(TYPE).toLowerCase() + + const image = + IMAGE ?? + { + fs: `${FORMAT} - ${size}`, + swap: size, + }[type] + + const labels = useMemo( + () => + [ + { label: TYPE, dataCy: 'type' }, + { + label: stringToBoolean(PERSISTENT) && 'PERSISTENT', + dataCy: 'persistent', + }, + { + label: stringToBoolean(READONLY) && 'READONLY', + dataCy: 'readonly', + }, + { + label: stringToBoolean(SAVE) && 'SAVE', + dataCy: 'save', + }, + { + label: stringToBoolean(CLONE) && 'CLONE', + dataCy: 'clone', + }, + ].filter(({ label } = {}) => Boolean(label)), + [TYPE, PERSISTENT, READONLY, SAVE, CLONE] + ) + + return ( + +
+
+ + {image} + + + {labels.map(({ label, dataCy }) => ( + + ))} + +
+
+ {`#${DISK_ID}`} + {TARGET && ( + + + {` ${TARGET}`} + + )} + {DATASTORE && ( + + + {` ${DATASTORE}`} + + )} + + + {` ${monitorSize}/${size}`} + +
+
+ {!IS_CONTEXT && !!actions.length && ( +
+ {actions.map((Action, idx) => ( + + ))} +
+ )} + {!!SNAPSHOTS?.length && ( + + {SNAPSHOTS?.map((snapshot) => ( + + ))} + + )} +
+ ) + } +) + +DiskCard.propTypes = { + disk: PropTypes.object.isRequired, + actions: PropTypes.any, + extraActionProps: PropTypes.object, + extraSnapshotActionProps: PropTypes.object, + snapshotActions: PropTypes.any, +} + +DiskCard.displayName = 'DiskCard' + +export default DiskCard diff --git a/src/fireedge/src/client/components/Cards/DiskSnapshotCard.js b/src/fireedge/src/client/components/Cards/DiskSnapshotCard.js new file mode 100644 index 0000000000..b69730c05f --- /dev/null +++ b/src/fireedge/src/client/components/Cards/DiskSnapshotCard.js @@ -0,0 +1,94 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo } from 'react' +import PropTypes from 'prop-types' +import { ModernTv } from 'iconoir-react' +import { Typography, Paper } from '@mui/material' + +import { StatusChip } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' +import { Translate } from 'client/components/HOC' + +import * as Helper from 'client/models/Helper' +import { prettyBytes } from 'client/utils' +import { T, DiskSnapshot } from 'client/constants' + +const DiskSnapshotCard = memo( + ({ snapshot = {}, actions = [], extraActionProps = {} }) => { + const classes = rowStyles() + + /** @type {DiskSnapshot} */ + const { + ID, + NAME, + ACTIVE, + DATE, + SIZE: SNAPSHOT_SIZE, + MONITOR_SIZE: SNAPSHOT_MONITOR_SIZE, + } = snapshot + + const isActive = Helper.stringToBoolean(ACTIVE) + const time = Helper.timeFromMilliseconds(+DATE) + const timeAgo = `created ${time.toRelative()}` + + const size = +SNAPSHOT_SIZE ? prettyBytes(+SNAPSHOT_SIZE, 'MB') : '-' + const monitorSize = +SNAPSHOT_MONITOR_SIZE + ? prettyBytes(+SNAPSHOT_MONITOR_SIZE, 'MB') + : '-' + + return ( + +
+
+ {NAME} + + {isActive && } />} + } /> + +
+
+ {`#${ID} ${timeAgo}`} + + + {` ${monitorSize}/${size}`} + +
+
+ {!!actions.length && ( +
+ {actions.map((Action, idx) => ( + + ))} +
+ )} +
+ ) + } +) + +DiskSnapshotCard.propTypes = { + snapshot: PropTypes.object.isRequired, + extraActionProps: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), +} + +DiskSnapshotCard.displayName = 'DiskSnapshotCard' + +export default DiskSnapshotCard diff --git a/src/fireedge/src/client/components/Cards/HostCard.js b/src/fireedge/src/client/components/Cards/HostCard.js index 71d921c681..99299fd861 100644 --- a/src/fireedge/src/client/components/Cards/HostCard.js +++ b/src/fireedge/src/client/components/Cards/HostCard.js @@ -13,119 +13,96 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo } from 'react' +import { memo, ReactElement } from 'react' import PropTypes from 'prop-types' +import { Server, ModernTv } from 'iconoir-react' import { Typography } from '@mui/material' -import makeStyles from '@mui/styles/makeStyles' -import { HardDrive as HostIcon } from 'iconoir-react' -import SelectCard, { Action } from 'client/components/Cards/SelectCard' import { - StatusBadge, + StatusCircle, StatusChip, LinearProgressWithLabel, } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' +import { Tr } from 'client/components/HOC' -import * as HostModel from 'client/models/Host' - -const useStyles = makeStyles({ - title: { - display: 'flex', - gap: '0.5rem', - }, - content: { - padding: '2em', - display: 'flex', - flexFlow: 'column', - gap: '1em', - }, -}) +import { getAllocatedInfo, getState } from 'client/models/Host' +import { T, Host } from 'client/constants' const HostCard = memo( - ({ value, isSelected, handleClick, actions }) => { - const classes = useStyles() - - const { ID, NAME, IM_MAD, VM_MAD } = value + /** + * @param {object} props - Props + * @param {Host} props.host - Host resource + * @param {object} props.rootProps - Props to root component + * @param {ReactElement} props.actions - Actions + * @returns {ReactElement} - Card + */ + ({ host, rootProps, actions }) => { + const classes = rowStyles() + const { ID, NAME, IM_MAD, VM_MAD, HOST_SHARE, CLUSTER, TEMPLATE } = host const { percentCpuUsed, percentCpuLabel, percentMemUsed, percentMemLabel } = - HostModel.getAllocatedInfo(value) + getAllocatedInfo(host) - const state = HostModel.getState(value) + const runningVms = HOST_SHARE?.RUNNING_VMS || 0 + const totalVms = [host?.VMS?.ID ?? []].flat().length || 0 + const { color: stateColor, name: stateName } = getState(host) - const mad = IM_MAD === VM_MAD ? IM_MAD : `${IM_MAD}/${VM_MAD}` + const labels = [...new Set([IM_MAD, VM_MAD])] return ( - ( - - ))} - icon={ - - - - } - title={ - - - {NAME} +
+
+ +
+
+
+ + {TEMPLATE?.NAME ?? NAME} - - - } - subheader={`#${ID}`} - isSelected={isSelected} - handleClick={handleClick} - > -
+ + {labels.map((label) => ( + + ))} + +
+
+ {`#${ID}`} + + + {` ${CLUSTER}`} + + + + {` ${runningVms} / ${totalVms}`} + +
+
+
- + {actions &&
{actions}
} +
) - }, - (prev, next) => - prev.isSelected === next.isSelected && - prev.value?.STATE === next.value?.STATE + } ) HostCard.propTypes = { - value: PropTypes.shape({ - ID: PropTypes.string.isRequired, - NAME: PropTypes.string.isRequired, - TYPE: PropTypes.string, - STATE: PropTypes.string, - IM_MAD: PropTypes.string, - VM_MAD: PropTypes.string, - HOST_SHARE: PropTypes.shape({ - CPU_USAGE: PropTypes.string, - TOTAL_CPU: PropTypes.string, - MEM_USAGE: PropTypes.string, - TOTAL_MEM: PropTypes.string, - }), + host: PropTypes.object, + rootProps: PropTypes.shape({ + className: PropTypes.string, }), - isSelected: PropTypes.bool, - handleClick: PropTypes.func, - actions: PropTypes.arrayOf( - PropTypes.shape({ - handleClick: PropTypes.func.isRequired, - icon: PropTypes.node.isRequired, - cy: PropTypes.string, - }) - ), -} - -HostCard.defaultProps = { - value: {}, - isSelected: false, - handleClick: undefined, - actions: undefined, + actions: PropTypes.any, } HostCard.displayName = 'HostCard' diff --git a/src/fireedge/src/client/components/Cards/NetworkCard.js b/src/fireedge/src/client/components/Cards/NetworkCard.js index a0e9e02f7b..614c091005 100644 --- a/src/fireedge/src/client/components/Cards/NetworkCard.js +++ b/src/fireedge/src/client/components/Cards/NetworkCard.js @@ -13,73 +13,82 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo } from 'react' +import { memo, ReactElement } from 'react' import PropTypes from 'prop-types' +import { Typography } from '@mui/material' +import { User, Group, Lock, Server, Cloud } from 'iconoir-react' -import { NetworkAlt as NetworkIcon } from 'iconoir-react' - -import SelectCard, { Action } from 'client/components/Cards/SelectCard' import { LinearProgressWithLabel } from 'client/components/Status' +import { getLeasesInfo, getTotalLeases } from 'client/models/VirtualNetwork' +import { rowStyles } from 'client/components/Tables/styles' const NetworkCard = memo( - ({ value, isSelected, handleClick, actions }) => { - const { ID, NAME, USED_LEASES = '', AR_POOL } = value + /** + * @param {object} props - Props + * @param {object} props.network - Network resource + * @param {object} props.rootProps - Props to root component + * @param {ReactElement} props.actions - Actions + * @returns {ReactElement} - Card + */ + ({ network, rootProps, actions }) => { + const classes = rowStyles() - const addresses = [AR_POOL?.AR ?? []].flat() - const totalLeases = addresses.reduce((res, ar) => +ar.SIZE + res, 0) + const { ID, NAME, UNAME, GNAME, LOCK, CLUSTERS, USED_LEASES, TEMPLATE } = + network - const percentOfUsed = (+USED_LEASES * 100) / +totalLeases || 0 - const percentLabel = `${USED_LEASES} / ${totalLeases} (${Math.round( - percentOfUsed - )}%)` + const totalLeases = getTotalLeases(network) + const { percentOfUsed, percentLabel } = getLeasesInfo(network) + const totalClusters = [CLUSTERS?.ID ?? []].flat().length || 0 + const provisionId = TEMPLATE?.PROVISION?.ID return ( - ( - - ))} - icon={} - title={NAME} - subheader={`#${ID}`} - isSelected={isSelected} - handleClick={handleClick} - > -
- +
+
+
+ {NAME} + {LOCK && } +
+
+ {`#${ID}`} + + + {` ${UNAME}`} + + + + {` ${GNAME}`} + + + + {` ${totalClusters}`} + + {provisionId && ( + + + {` ${provisionId}`} + + )} +
- +
+ +
+ {actions &&
{actions}
} +
) - }, - (prev, next) => prev.isSelected === next.isSelected + } ) NetworkCard.propTypes = { - value: PropTypes.shape({ - ID: PropTypes.string.isRequired, - NAME: PropTypes.string.isRequired, - TYPE: PropTypes.string, - STATE: PropTypes.string, - USED_LEASES: PropTypes.string, - AR_POOL: PropTypes.shape({ - AR: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), - }), + network: PropTypes.object, + rootProps: PropTypes.shape({ + className: PropTypes.string, }), - isSelected: PropTypes.bool, - handleClick: PropTypes.func, - actions: PropTypes.arrayOf( - PropTypes.shape({ - handleClick: PropTypes.func.isRequired, - icon: PropTypes.node.isRequired, - cy: PropTypes.string, - }) - ), -} - -NetworkCard.defaultProps = { - value: {}, - isSelected: false, - handleClick: undefined, - actions: undefined, + actions: PropTypes.any, } NetworkCard.displayName = 'NetworkCard' diff --git a/src/fireedge/src/client/components/Cards/NicCard.js b/src/fireedge/src/client/components/Cards/NicCard.js new file mode 100644 index 0000000000..f41fe48b77 --- /dev/null +++ b/src/fireedge/src/client/components/Cards/NicCard.js @@ -0,0 +1,161 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo } from 'react' +import PropTypes from 'prop-types' + +import { + useMediaQuery, + Typography, + Box, + Paper, + Stack, + Divider, +} from '@mui/material' + +import { rowStyles } from 'client/components/Tables/styles' +import MultipleTags from 'client/components/MultipleTags' +import SecurityGroupCard from 'client/components/Cards/SecurityGroupCard' + +import { Translate } from 'client/components/HOC' +import { T, Nic, NicAlias } from 'client/constants' + +const NicCard = memo( + ({ + nic = {}, + actions = [], + extraActionProps = {}, + aliasActions = [], + extraAliasActionProps = {}, + }) => { + const classes = rowStyles() + const isMobile = useMediaQuery((theme) => theme.breakpoints.down('md')) + + /** @type {Nic|NicAlias} */ + const { + NIC_ID, + NETWORK = '-', + IP, + MAC, + PCI_ID, + PARENT, + ADDRESS, + ALIAS, + SECURITY_GROUPS, + } = nic + + const isAlias = !!PARENT?.length + const isPciDevice = PCI_ID !== undefined + + const dataCy = isAlias ? 'alias' : 'nic' + const tags = [ + { text: IP, dataCy: `${dataCy}-ip` }, + { text: MAC, dataCy: `${dataCy}-mac` }, + { text: ADDRESS, dataCy: `${dataCy}-address` }, + ].filter(({ text } = {}) => Boolean(text)) + + return ( + + +
+ + {`${NIC_ID} | ${NETWORK}`} + + + + +
+
+ {!isMobile && + !isPciDevice && + actions.map((Action, idx) => ( + + ))} + {!!ALIAS?.length && ( + + {ALIAS?.map((alias) => ( + + ))} + + )} + {Array.isArray(SECURITY_GROUPS) && !!SECURITY_GROUPS?.length && ( + + + + + + } spacing={1}> + {SECURITY_GROUPS?.map((securityGroup, idx) => { + const key = `nic${NIC_ID}-${idx}-${securityGroup.NAME}` + + return ( + + ) + })} + + + )} +
+ ) + } +) + +NicCard.propTypes = { + nic: PropTypes.object, + actions: PropTypes.array, + extraActionProps: PropTypes.object, + aliasActions: PropTypes.array, + extraAliasActionProps: PropTypes.object, +} + +NicCard.displayName = 'NicCard' + +NicCard.displayName = 'NicCard' + +export default NicCard diff --git a/src/fireedge/src/client/components/Cards/ProvisionCard.js b/src/fireedge/src/client/components/Cards/ProvisionCard.js index c591dcbce1..f52b43577c 100644 --- a/src/fireedge/src/client/components/Cards/ProvisionCard.js +++ b/src/fireedge/src/client/components/Cards/ProvisionCard.js @@ -110,7 +110,7 @@ ProvisionCard.propTypes = { handleClick: PropTypes.func, isProvider: PropTypes.bool, image: PropTypes.string, - deleteAction: PropTypes.func, + deleteAction: PropTypes.object, actions: PropTypes.arrayOf( PropTypes.shape({ handleClick: PropTypes.func.isRequired, diff --git a/src/fireedge/src/client/components/Cards/ScheduleActionCard.js b/src/fireedge/src/client/components/Cards/ScheduleActionCard.js index 2194489f25..2497fc2f2d 100644 --- a/src/fireedge/src/client/components/Cards/ScheduleActionCard.js +++ b/src/fireedge/src/client/components/Cards/ScheduleActionCard.js @@ -20,7 +20,6 @@ import { useTheme, Typography, Paper, Stack } from '@mui/material' import Timer from 'client/components/Timer' import { StatusChip } from 'client/components/Status' -import { UpdateSchedButton, DeleteSchedButton } from 'client/components/Buttons' import { rowStyles } from 'client/components/Tables/styles' import { @@ -32,92 +31,77 @@ import { timeFromMilliseconds } from 'client/models/Helper' import { sentenceCase } from 'client/utils' import { T } from 'client/constants' -const ScheduleActionCard = memo( - ({ vm, schedule, handleRemove, handleUpdate }) => { - const classes = rowStyles() - const { palette } = useTheme() +const ScheduleActionCard = memo(({ schedule, actions }) => { + const classes = rowStyles() + const { palette } = useTheme() - const { ID, ACTION, TIME, MESSAGE, DONE, WARNING } = schedule + const { ID, ACTION, TIME, MESSAGE, DONE, WARNING } = schedule - const titleAction = `#${ID} ${sentenceCase(ACTION)}` - const timeIsRelative = isRelative(TIME) + const titleAction = `#${ID} ${sentenceCase(ACTION)}` + const timeIsRelative = isRelative(TIME) - const time = timeIsRelative ? getPeriodicityByTimeInSeconds(TIME) : TIME - const formatTime = - !timeIsRelative && timeFromMilliseconds(+TIME).toFormat('ff') - const formatDoneTime = DONE && timeFromMilliseconds(+DONE).toFormat('ff') + const time = timeIsRelative ? getPeriodicityByTimeInSeconds(TIME) : TIME + const formatTime = + !timeIsRelative && timeFromMilliseconds(+TIME).toFormat('ff') + const formatDoneTime = DONE && timeFromMilliseconds(+DONE).toFormat('ff') - const { repeat, end } = getRepeatInformation(schedule) + const { repeat, end } = getRepeatInformation(schedule) - const noMore = !repeat && DONE - // const timeIsPast = new Date(+TIME * 1000) < new Date() + const noMore = !repeat && DONE - return ( - -
-
- {titleAction} - {MESSAGE && ( - - - - )} -
- - {repeat && {repeat}} - {end && {end}} - {DONE && ( - - - - )} - {!noMore && ( - <> - - {timeIsRelative ? ( - {Object.values(time).join(' ')} - ) : ( - - - - )} - - {WARNING && } - - )} - + return ( + +
+
+ {titleAction} + {MESSAGE && ( + + + + )}
- {(handleUpdate || handleRemove) && ( -
- {!noMore && handleUpdate && ( - - )} - {handleRemove && ( - - )} -
- )} - - ) - } -) + + {repeat && {repeat}} + {end && {end}} + {DONE && ( + + + + )} + {!noMore && ( + <> + + {timeIsRelative ? ( + {Object.values(time).join(' ')} + ) : ( + + + + )} + + {WARNING && } + + )} + +
+ {actions && ( +
+ {typeof actions === 'function' ? actions({ noMore }) : actions} +
+ )} +
+ ) +}) ScheduleActionCard.propTypes = { - vm: PropTypes.object, schedule: PropTypes.object.isRequired, - handleRemove: PropTypes.func, - handleUpdate: PropTypes.func, + actions: PropTypes.any, } ScheduleActionCard.displayName = 'ScheduleActionCard' diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/SecGroup.js b/src/fireedge/src/client/components/Cards/SecurityGroupCard.js similarity index 54% rename from src/fireedge/src/client/components/Tabs/Vm/Network/SecGroup.js rename to src/fireedge/src/client/components/Cards/SecurityGroupCard.js index 3455f03943..948629c5f3 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Network/SecGroup.js +++ b/src/fireedge/src/client/components/Cards/SecurityGroupCard.js @@ -16,82 +16,45 @@ import { memo } from 'react' import PropTypes from 'prop-types' -import { styled, useMediaQuery } from '@mui/material' -import Typography from '@mui/material/Typography' +import { useMediaQuery, Typography } from '@mui/material' import MultipleTags from 'client/components/MultipleTags' +import { rowStyles } from 'client/components/Tables/styles' +import { SecurityGroup } from 'client/constants' -const DATACY_SECGROUP = 'securitygroup-' - -const Row = styled('div')({ - display: 'flex', - width: '100%', - gap: '0.5em', - alignItems: 'center', - flexWrap: 'nowrap', -}) - -const Labels = styled('span')({ - display: 'inline-flex', - gap: '0.5em', - alignItems: 'center', -}) - -const SecGroup = memo(({ index, securityGroup }) => { +const SecurityGroupCard = memo(({ securityGroup, ...props }) => { + const classes = rowStyles() const isMobile = useMediaQuery((theme) => theme.breakpoints.down('md')) + /** @type {SecurityGroup} */ const { ID, NAME, PROTOCOL, RULE_TYPE, ICMP_TYPE, RANGE, NETWORK_ID } = securityGroup const tags = [ - { - text: PROTOCOL, - dataCy: `${DATACY_SECGROUP}protocol`, - }, - { - text: RULE_TYPE, - dataCy: `${DATACY_SECGROUP}ruletype`, - }, - { - text: RANGE, - dataCy: `${DATACY_SECGROUP}range`, - }, - { - text: NETWORK_ID, - dataCy: `${DATACY_SECGROUP}networkid`, - }, - { - text: ICMP_TYPE, - dataCy: `${DATACY_SECGROUP}icmp_type`, - }, + { text: PROTOCOL, dataCy: 'protocol' }, + { text: RULE_TYPE, dataCy: 'ruletype' }, + { text: RANGE, dataCy: 'range' }, + { text: NETWORK_ID, dataCy: 'networkid' }, + { text: ICMP_TYPE, dataCy: 'icmp-type' }, ].filter(({ text } = {}) => Boolean(text)) return ( - - +
+ {`${ID} | ${NAME}`} - + - - + +
) }) -SecGroup.displayName = 'SecGroup' - -SecGroup.propTypes = { - index: PropTypes.number, - securityGroup: PropTypes.shape({ - ID: PropTypes.string, - SECURITY_GROUP_ID: PropTypes.string, - NAME: PropTypes.string, - PROTOCOL: PropTypes.string, - RULE_TYPE: PropTypes.string, - ICMP_TYPE: PropTypes.string, - RANGE: PropTypes.string, - NETWORK_ID: PropTypes.string, - }), +SecurityGroupCard.propTypes = { + securityGroup: PropTypes.object, + 'data-cy': PropTypes.string, } -export default SecGroup +SecurityGroupCard.displayName = 'SecurityGroupCard' + +export default SecurityGroupCard diff --git a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/Item.js b/src/fireedge/src/client/components/Cards/SnapshotCard.js similarity index 52% rename from src/fireedge/src/client/components/Tabs/Vm/Snapshot/Item.js rename to src/fireedge/src/client/components/Cards/SnapshotCard.js index 5e0d456d5a..2103f8947c 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/Item.js +++ b/src/fireedge/src/client/components/Cards/SnapshotCard.js @@ -13,55 +13,58 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { memo } from 'react' import PropTypes from 'prop-types' import { Typography, Paper } from '@mui/material' -import * as Actions from 'client/components/Tabs/Vm/Snapshot/Actions' import { rowStyles } from 'client/components/Tables/styles' - import * as Helper from 'client/models/Helper' -import { VM_ACTIONS } from 'client/constants' +import { Snapshot } from 'client/constants' -const SnapshotItem = ({ snapshot, actions = [] }) => { - const classes = rowStyles() +const SnapshotCard = memo( + ({ snapshot, actions = [], extraActionProps = {} }) => { + const classes = rowStyles() - const { SNAPSHOT_ID, NAME, TIME } = snapshot + /** @type {Snapshot} */ + const { SNAPSHOT_ID, NAME, TIME } = snapshot - const time = Helper.timeFromMilliseconds(+TIME) - const timeAgo = `created ${time.toRelative()}` + const time = Helper.timeFromMilliseconds(+TIME) + const timeAgo = `created ${time.toRelative()}` - return ( - -
-
- {NAME} + return ( + +
+
+ {NAME} +
+
+ + {`#${SNAPSHOT_ID} ${timeAgo}`} + +
-
- - {`#${SNAPSHOT_ID} ${timeAgo}`} - -
-
- {!!actions.length && ( -
- {actions?.includes?.(VM_ACTIONS.SNAPSHOT_REVERT) && ( - - )} - {actions?.includes?.(VM_ACTIONS.SNAPSHOT_DELETE) && ( - - )} -
- )} - - ) -} + {!!actions.length && ( +
+ {actions.map((Action, idx) => ( + + ))} +
+ )} + + ) + } +) -SnapshotItem.propTypes = { +SnapshotCard.propTypes = { snapshot: PropTypes.object.isRequired, - actions: PropTypes.arrayOf(PropTypes.string), + actions: PropTypes.array, + extraActionProps: PropTypes.object, } -SnapshotItem.displayName = 'SnapshotItem' +SnapshotCard.displayName = 'SnapshotCard' -export default SnapshotItem +export default SnapshotCard diff --git a/src/fireedge/src/client/components/Cards/VirtualMachineCard.js b/src/fireedge/src/client/components/Cards/VirtualMachineCard.js index 2c5e7a3d85..eb671e5d4a 100644 --- a/src/fireedge/src/client/components/Cards/VirtualMachineCard.js +++ b/src/fireedge/src/client/components/Cards/VirtualMachineCard.js @@ -13,62 +13,86 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo } from 'react' +import { ReactElement, memo } from 'react' import PropTypes from 'prop-types' -import { ViewGrid as VmIcon } from 'iconoir-react' -import SelectCard, { Action } from 'client/components/Cards/SelectCard' -import { StatusBadge } from 'client/components/Status' -import { getState } from 'client/models/VirtualMachine' +import { User, Group, Lock, HardDrive } from 'iconoir-react' +import { Stack, Typography } from '@mui/material' + +import Timer from 'client/components/Timer' +import MultipleTags from 'client/components/MultipleTags' +import { StatusCircle } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' +import { getState, getLastHistory } from 'client/models/VirtualMachine' +import { timeFromMilliseconds } from 'client/models/Helper' +import { VM } from 'client/constants' const VirtualMachineCard = memo( - ({ value, isSelected, handleClick, actions }) => { - const { ID, NAME } = value - const { color, name } = getState(value) ?? {} + /** + * @param {object} props - Props + * @param {VM} props.vm - Virtual machine resource + * @param {object} props.rootProps - Props to root component + * @returns {ReactElement} - Card + */ + ({ vm, rootProps }) => { + const classes = rowStyles() + const { ID, NAME, UNAME, GNAME, IPS, STIME, ETIME, LOCK } = vm + + const HOSTNAME = getLastHistory(vm)?.HOSTNAME ?? '--' + const time = timeFromMilliseconds(+ETIME || +STIME) + + const { color: stateColor, name: stateName } = getState(vm) return ( - ( - - ))} - skeletonHeight={75} - dataCy={`vm-${ID}`} - handleClick={handleClick} - icon={ - - - - } - isSelected={isSelected} - subheader={`#${ID}`} - title={NAME} - /> +
+
+ +
+
+
+ + {NAME} + + + {LOCK && } + +
+
+ + {`#${ID} ${+ETIME ? 'done' : 'started'} `} + + + + + {` ${UNAME}`} + + + + {` ${GNAME}`} + + + + {` ${HOSTNAME}`} + +
+
+ {!!IPS?.length && ( +
+ + + +
+ )} +
) - }, - (prev, next) => - prev.isSelected === next.isSelected && - prev.value.STATE === next.value.STATE && - prev.value?.LCM_STATE === next.value?.LCM_STATE + } ) VirtualMachineCard.propTypes = { - handleClick: PropTypes.func, - isSelected: PropTypes.bool, - value: PropTypes.object, - actions: PropTypes.arrayOf( - PropTypes.shape({ - handleClick: PropTypes.func.isRequired, - icon: PropTypes.object.isRequired, - cy: PropTypes.string, - }) - ), -} - -VirtualMachineCard.defaultProps = { - handleClick: undefined, - isSelected: false, - value: {}, - actions: undefined, + vm: PropTypes.object, + rootProps: PropTypes.shape({ + className: PropTypes.string, + }), } VirtualMachineCard.displayName = 'VirtualMachineCard' diff --git a/src/fireedge/src/client/components/Cards/VmTemplateCard.js b/src/fireedge/src/client/components/Cards/VmTemplateCard.js new file mode 100644 index 0000000000..635960e91a --- /dev/null +++ b/src/fireedge/src/client/components/Cards/VmTemplateCard.js @@ -0,0 +1,107 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, memo, useMemo } from 'react' +import PropTypes from 'prop-types' + +import { User, Group, Lock } from 'iconoir-react' +import { Typography } from '@mui/material' + +import Timer from 'client/components/Timer' +import { StatusChip } from 'client/components/Status' +import { rowStyles } from 'client/components/Tables/styles' +import Image from 'client/components/Image' + +import { timeFromMilliseconds } from 'client/models/Helper' +import { isExternalURL } from 'client/utils' +import { VM, LOGO_IMAGES_URL } from 'client/constants' + +const VmTemplateCard = memo( + /** + * @param {object} props - Props + * @param {VM} props.template - Virtual machine resource + * @param {object} props.rootProps - Props to root component + * @returns {ReactElement} - Card + */ + ({ template, rootProps }) => { + const classes = rowStyles() + const { + ID, + NAME, + UNAME, + GNAME, + REGTIME, + LOCK, + VROUTER, + LOGO = '', + } = template + + const [logoSource] = useMemo(() => { + const external = isExternalURL(LOGO) + const cleanLogoAttribute = String(LOGO).split('/').at(-1) + const src = external ? LOGO : `${LOGO_IMAGES_URL}/${cleanLogoAttribute}` + + return [src, external] + }, [LOGO]) + + const time = timeFromMilliseconds(+REGTIME) + + return ( +
+
+ logo +
+
+
+ {NAME} + + {LOCK && } + {VROUTER && } + +
+
+ + {`#${ID} registered `} + + + + + {` ${UNAME}`} + + + + {` ${GNAME}`} + +
+
+
+ ) + } +) + +VmTemplateCard.propTypes = { + template: PropTypes.object, + rootProps: PropTypes.shape({ + className: PropTypes.string, + }), +} + +VmTemplateCard.displayName = 'VmTemplateCard' + +export default VmTemplateCard diff --git a/src/fireedge/src/client/components/Cards/index.js b/src/fireedge/src/client/components/Cards/index.js index 0219a1c8e9..02adbf8ed5 100644 --- a/src/fireedge/src/client/components/Cards/index.js +++ b/src/fireedge/src/client/components/Cards/index.js @@ -18,16 +18,22 @@ import ApplicationNetworkCard from 'client/components/Cards/ApplicationNetworkCa import ApplicationTemplateCard from 'client/components/Cards/ApplicationTemplateCard' import ClusterCard from 'client/components/Cards/ClusterCard' import DatastoreCard from 'client/components/Cards/DatastoreCard' +import DiskCard from 'client/components/Cards/DiskCard' +import DiskSnapshotCard from 'client/components/Cards/DiskSnapshotCard' import EmptyCard from 'client/components/Cards/EmptyCard' import HostCard from 'client/components/Cards/HostCard' import NetworkCard from 'client/components/Cards/NetworkCard' +import NicCard from 'client/components/Cards/NicCard' import PolicyCard from 'client/components/Cards/PolicyCard' import ProvisionCard from 'client/components/Cards/ProvisionCard' import ProvisionTemplateCard from 'client/components/Cards/ProvisionTemplateCard' import ScheduleActionCard from 'client/components/Cards/ScheduleActionCard' +import SecurityGroupCard from 'client/components/Cards/SecurityGroupCard' +import SnapshotCard from 'client/components/Cards/SnapshotCard' import SelectCard from 'client/components/Cards/SelectCard' import TierCard from 'client/components/Cards/TierCard' import VirtualMachineCard from 'client/components/Cards/VirtualMachineCard' +import VmTemplateCard from 'client/components/Cards/VmTemplateCard' import WavesCard from 'client/components/Cards/WavesCard' export { @@ -36,15 +42,21 @@ export { ApplicationTemplateCard, ClusterCard, DatastoreCard, + DiskCard, + DiskSnapshotCard, EmptyCard, HostCard, NetworkCard, + NicCard, PolicyCard, ProvisionCard, ProvisionTemplateCard, ScheduleActionCard, + SecurityGroupCard, + SnapshotCard, SelectCard, TierCard, VirtualMachineCard, + VmTemplateCard, WavesCard, } diff --git a/src/fireedge/src/client/components/Charts/CircleChart.js b/src/fireedge/src/client/components/Charts/CircleChart.js index d183aa576b..1095bfc376 100644 --- a/src/fireedge/src/client/components/Charts/CircleChart.js +++ b/src/fireedge/src/client/components/Charts/CircleChart.js @@ -90,7 +90,7 @@ const CircleChart = memo( diff --git a/src/fireedge/src/client/components/DebugLog/index.js b/src/fireedge/src/client/components/DebugLog/index.js index c6786ed200..610be5dd4b 100644 --- a/src/fireedge/src/client/components/DebugLog/index.js +++ b/src/fireedge/src/client/components/DebugLog/index.js @@ -28,6 +28,7 @@ const debugLogStyles = makeStyles((theme) => ({ display: 'flex', flexFlow: 'column', height: '100%', + overflow: 'auto', }, containerScroll: { width: '100%', diff --git a/src/fireedge/src/client/components/Dialogs/DialogConfirmation.js b/src/fireedge/src/client/components/Dialogs/DialogConfirmation.js index d594d38d82..9da45ae0ee 100644 --- a/src/fireedge/src/client/components/Dialogs/DialogConfirmation.js +++ b/src/fireedge/src/client/components/Dialogs/DialogConfirmation.js @@ -122,7 +122,11 @@ const DialogConfirmation = memo( )} {children && ( - + {children} )} diff --git a/src/fireedge/src/client/components/Footer/index.js b/src/fireedge/src/client/components/Footer/index.js index 3a8ec1c340..667674712f 100644 --- a/src/fireedge/src/client/components/Footer/index.js +++ b/src/fireedge/src/client/components/Footer/index.js @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useEffect } from 'react' +import { memo } from 'react' import { styled, Link, Typography } from '@mui/material' -import { useFetch } from 'client/hooks' -import { useSystem, useSystemApi } from 'client/features/One' +import { useGetOneVersionQuery } from 'client/features/OneApi/system' import { StatusChip } from 'client/components/Status' import { BY } from 'client/constants' @@ -44,13 +43,7 @@ const HeartIcon = styled('span')(({ theme }) => ({ })) const Footer = memo(() => { - const { version } = useSystem() - const { getOneVersion } = useSystemApi() - const { fetchRequest } = useFetch(getOneVersion) - - useEffect(() => { - !version && fetchRequest() - }, []) + const { data: version } = useGetOneVersionQuery() return ( diff --git a/src/fireedge/src/client/components/FormControl/SubmitButton.js b/src/fireedge/src/client/components/FormControl/SubmitButton.js index c92ba1b22e..2d5b228c7d 100644 --- a/src/fireedge/src/client/components/FormControl/SubmitButton.js +++ b/src/fireedge/src/client/components/FormControl/SubmitButton.js @@ -63,7 +63,7 @@ const ButtonComponent = forwardRef( ) ) -const TooltipComponent = ({ tooltip, tooltipProps, children }) => ( +const TooltipComponent = ({ tooltip, tooltipprops, children }) => ( ( @@ -71,7 +71,7 @@ const TooltipComponent = ({ tooltip, tooltipProps, children }) => ( arrow placement="bottom" title={{tooltip}} - {...tooltipProps} + {...tooltipprops} > {wrapperChildren} @@ -118,7 +118,7 @@ export const SubmitButtonPropTypes = { endicon: PropTypes.node, label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), tooltip: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), - tooltipProps: PropTypes.object, + tooltipprops: PropTypes.object, isSubmitting: PropTypes.bool, disabled: PropTypes.bool, className: PropTypes.string, diff --git a/src/fireedge/src/client/components/FormStepper/MobileStepper.js b/src/fireedge/src/client/components/FormStepper/MobileStepper.js index 08e506034f..4911e794a5 100644 --- a/src/fireedge/src/client/components/FormStepper/MobileStepper.js +++ b/src/fireedge/src/client/components/FormStepper/MobileStepper.js @@ -23,7 +23,7 @@ import { NavArrowRight as NextIcon, } from 'iconoir-react' -import { Translate, labelCanBeTranslated } from 'client/components/HOC' +import { Tr, Translate, labelCanBeTranslated } from 'client/components/HOC' import { T } from 'client/constants' const useStyles = makeStyles((theme) => ({ @@ -64,11 +64,9 @@ const CustomMobileStepper = ({ {Boolean(errors[id]) && ( - {labelCanBeTranslated(label) ? ( - - ) : ( - errors[id]?.message - )} + {labelCanBeTranslated(label) + ? Tr(errors[id]?.message) + : errors[id]?.message} )} diff --git a/src/fireedge/src/client/components/FormStepper/Stepper.js b/src/fireedge/src/client/components/FormStepper/Stepper.js index 81f326b374..b2a53a9c2c 100644 --- a/src/fireedge/src/client/components/FormStepper/Stepper.js +++ b/src/fireedge/src/client/components/FormStepper/Stepper.js @@ -112,7 +112,7 @@ const CustomStepper = ({ StepIconComponent={StepIconStyled} error={Boolean(errors[id]?.message)} > - {labelCanBeTranslated(label) ? : label} + {labelCanBeTranslated(label) ? Tr(label) : label} diff --git a/src/fireedge/src/client/components/FormStepper/index.js b/src/fireedge/src/client/components/FormStepper/index.js index c349cff7df..3855e94221 100644 --- a/src/fireedge/src/client/components/FormStepper/index.js +++ b/src/fireedge/src/client/components/FormStepper/index.js @@ -22,17 +22,15 @@ import { } from 'react' import PropTypes from 'prop-types' -import { sprintf } from 'sprintf-js' import { BaseSchema } from 'yup' import { useFormContext } from 'react-hook-form' -import { DevTool } from '@hookform/devtools' import { useMediaQuery } from '@mui/material' import { useGeneral } from 'client/features/General' import CustomMobileStepper from 'client/components/FormStepper/MobileStepper' import CustomStepper from 'client/components/FormStepper/Stepper' import SkeletonStepsForm from 'client/components/FormStepper/Skeleton' -import { groupBy, Step, isDevelopment } from 'client/utils' +import { groupBy, Step } from 'client/utils' import { T } from 'client/constants' const FIRST_STEP = 0 @@ -50,7 +48,6 @@ const FIRST_STEP = 0 const FormStepper = ({ steps = [], schema, onSubmit }) => { const isMobile = useMediaQuery((theme) => theme.breakpoints.only('xs')) const { - control, watch, reset, formState: { errors }, @@ -82,28 +79,17 @@ const FormStepper = ({ steps = [], schema, onSubmit }) => { return { id, data: stepData, ...step } } - const setErrors = ({ inner = [], ...rest } = {}) => { + const setErrors = ({ inner = [], message = { word: 'Error' } } = {}) => { const errorsByPath = groupBy(inner, 'path') ?? {} const totalErrors = Object.keys(errorsByPath).length - totalErrors > 0 - ? setError(stepId, { - type: 'manual', - message: [T.ErrorsOcurred, totalErrors], - }) - : setError(stepId, rest) + const translationError = + totalErrors > 0 ? [T.ErrorsOcurred, totalErrors] : Object.values(message) - inner?.forEach(({ path, type, errors: message }) => { - if (isDevelopment()) { - // the package @hookform/devtools requires message as string - const [key, ...values] = [message].flat() - setError(`${stepId}.${path}`, { - type, - message: sprintf(key, ...values), - }) - } else { - setError(`${stepId}.${path}`, { type, message }) - } + setError(stepId, { type: 'manual', message: translationError }) + + inner?.forEach(({ path, type, errors: innerMessage }) => { + setError(`${stepId}.${path}`, { type, message: innerMessage }) }) } @@ -202,8 +188,6 @@ const FormStepper = ({ steps = [], schema, onSubmit }) => { )} {/* FORM CONTENT */} {Content && } - - {isDevelopment() && } ) } diff --git a/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/BasicConfiguration/schema.js b/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/BasicConfiguration/schema.js index dead4a97a9..88285d6d16 100644 --- a/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/BasicConfiguration/schema.js +++ b/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/BasicConfiguration/schema.js @@ -16,7 +16,8 @@ import { string, boolean, ObjectSchema } from 'yup' import { makeStyles } from '@mui/styles' -import { useSystem, useDatastore } from 'client/features/One' +import { useGetOneConfigQuery } from 'client/features/OneApi/system' +import { useGetDatastoresQuery } from 'client/features/OneApi/datastore' import { ImagesTable, VmsTable, @@ -134,8 +135,8 @@ const RES_TABLE = { .default(() => undefined), grid: { md: 12 }, fieldProps: (type) => { - const { config: oneConfig } = useSystem() - const datastores = useDatastore() + const { data: oneConfig = {} } = useGetOneConfigQuery() + const { data: datastores = [] } = useGetDatastoresQuery() const classes = useTableStyles() return { diff --git a/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/MarketplacesTable/index.js b/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/MarketplacesTable/index.js index 5f30ae7220..0ea5380834 100644 --- a/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/MarketplacesTable/index.js +++ b/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/Steps/MarketplacesTable/index.js @@ -16,7 +16,7 @@ import PropTypes from 'prop-types' import { useFormContext } from 'react-hook-form' -import { useSystem } from 'client/features/One' +import { useGetOneConfigQuery } from 'client/features/OneApi/system' import { MarketplacesTable } from 'client/components/Tables' import { SCHEMA } from 'client/components/Forms/MarketplaceApp/CreateForm/Steps/MarketplacesTable/schema' import { Step } from 'client/utils' @@ -27,7 +27,7 @@ export const STEP_ID = 'marketplace' const Content = ({ data }) => { const { NAME } = data?.[0] ?? {} const { setValue } = useFormContext() - const { config: oneConfig } = useSystem() + const { data: oneConfig = {} } = useGetOneConfigQuery() const handleSelectedRows = (rows) => { const { original = {} } = rows?.[0] ?? {} diff --git a/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/index.js b/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/index.js index 608d65262f..341b8e41e0 100644 --- a/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/index.js +++ b/src/fireedge/src/client/components/Forms/MarketplaceApp/CreateForm/index.js @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useEffect, useMemo, JSXElementConstructor } from 'react' +import { useMemo, JSXElementConstructor } from 'react' import PropTypes from 'prop-types' import { useForm, FormProvider } from 'react-hook-form' import { yupResolver } from '@hookform/resolvers/yup' -import { useDatastoreApi } from 'client/features/One' import FormStepper from 'client/components/FormStepper' import Steps from 'client/components/Forms/MarketplaceApp/CreateForm/Steps' @@ -32,7 +31,6 @@ import Steps from 'client/components/Forms/MarketplaceApp/CreateForm/Steps' * @returns {JSXElementConstructor} Form component */ const CreateForm = ({ initialValues, onSubmit }) => { - const { getDatastores } = useDatastoreApi() const stepsForm = useMemo(() => Steps(initialValues, initialValues), []) const { steps, defaultValues, resolver, transformBeforeSubmit } = stepsForm @@ -42,10 +40,6 @@ const CreateForm = ({ initialValues, onSubmit }) => { resolver: yupResolver(resolver?.()), }) - useEffect(() => { - getDatastores() - }, []) - return ( [!isUpdate && NAME, DESCRIPTION].filter(Boolean) +/** + * @param {object} config - Form configuration + * @param {boolean} [config.isUpdate] - Form is updating the provider + * @returns {ObjectSchema} - Schema + */ export const STEP_FORM_SCHEMA = ({ isUpdate }) => - yup.object(getValidationFromFields(FORM_FIELDS({ isUpdate }))) + object(getValidationFromFields(FORM_FIELDS({ isUpdate }))) diff --git a/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/index.js b/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/index.js index 15130918c7..dfed1010ad 100644 --- a/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/index.js +++ b/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/index.js @@ -18,7 +18,7 @@ import { useEffect, useState } from 'react' import PropTypes from 'prop-types' import { useFormContext } from 'react-hook-form' -import { useAuth } from 'client/features/Auth' +import { useGetProviderConfigQuery } from 'client/features/OneApi/provider' import FormWithSchema from 'client/components/Forms/FormWithSchema' import { EmptyCard } from 'client/components/Cards' @@ -39,7 +39,7 @@ let fileCredentials = false const Content = ({ isUpdate }) => { const [fields, setFields] = useState([]) - const { providerConfig } = useAuth() + const { data: providerConfig } = useGetProviderConfigQuery() const { watch } = useFormContext() useEffect(() => { diff --git a/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/schema.js b/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/schema.js index bb07c8334c..7835fcf09f 100644 --- a/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/schema.js +++ b/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Connection/schema.js @@ -13,21 +13,26 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import * as yup from 'yup' +import { string, object, ObjectSchema } from 'yup' import { INPUT_TYPES } from 'client/constants' -import { getValidationFromFields, prettyBytes } from 'client/utils' +import { Field, getValidationFromFields, prettyBytes } from 'client/utils' const MAX_SIZE_JSON = 102_400 const JSON_FORMAT = 'application/json' const CREDENTIAL_INPUT = 'credentials' +/** + * @param {object} config - Form configuration + * @param {object} config.connection - Provider connection + * @param {boolean} config.fileCredentials - Provider needs file with credentials + * @returns {Field[]} - List of fields + */ export const FORM_FIELDS = ({ connection, fileCredentials }) => Object.entries(connection)?.map(([name, label]) => { const isInputFile = fileCredentials && String(name).toLowerCase() === CREDENTIAL_INPUT - let validation = yup.string().trim().required().default(undefined) + let validation = string().trim().required().default(undefined) if (isInputFile) { validation = validation.isBase64() @@ -62,5 +67,9 @@ export const FORM_FIELDS = ({ connection, fileCredentials }) => } }) -export const STEP_FORM_SCHEMA = (props) => - yup.object(getValidationFromFields(FORM_FIELDS(props))) +/** + * @param {object} config - Form configuration + * @returns {ObjectSchema} - Schema + */ +export const STEP_FORM_SCHEMA = (config) => + object(getValidationFromFields(FORM_FIELDS(config))) diff --git a/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Template/index.js b/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Template/index.js index fa99c6d0b4..fb9caef795 100644 --- a/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Template/index.js +++ b/src/fireedge/src/client/components/Forms/Provider/CreateForm/Steps/Template/index.js @@ -27,8 +27,8 @@ import { NavArrowRight } from 'iconoir-react' import { marked } from 'marked' import { useListForm } from 'client/hooks' -import { useAuth } from 'client/features/Auth' -import { useProvisionTemplate } from 'client/features/One' +import { useGetProviderConfigQuery } from 'client/features/OneApi/provider' +import { useGetProvisionTemplatesQuery } from 'client/features/OneApi/provision' import { ListCards } from 'client/components/List' import { ProvisionTemplateCard } from 'client/components/Cards' import { Step, sanitize, deepmerge } from 'client/utils' @@ -76,8 +76,8 @@ Description.propTypes = { description: PropTypes.string } // ---------------------------------------------------------- const Content = ({ data, setFormData }) => { - const provisionTemplates = useProvisionTemplate() - const { providerConfig } = useAuth() + const { data: provisionTemplates = {} } = useGetProvisionTemplatesQuery() + const { data: providerConfig = {} } = useGetProviderConfigQuery() const templateSelected = data?.[0] const provisionTypes = useMemo( @@ -174,7 +174,7 @@ const Content = ({ data, setFormData }) => { inputProps={{ 'data-cy': 'select-provision-type' }} labelId="select-provision-type-label" native - style={{ marginTop: '1em', minWidth: '8em' }} + sx={{ marginTop: '1em', minWidth: '8em' }} onChange={handleChangeProvision} value={provisionSelected} variant="outlined" @@ -195,7 +195,7 @@ const Content = ({ data, setFormData }) => { inputProps={{ 'data-cy': 'select-provider-type' }} labelId="select-provider-type-label" native - style={{ marginTop: '1em', minWidth: '8em' }} + sx={{ marginTop: '1em', minWidth: '8em' }} onChange={handleChangeProvider} value={providerSelected} variant="outlined" @@ -212,7 +212,7 @@ const Content = ({ data, setFormData }) => { {/* -- DESCRIPTION -- */} {providerDescription && } - + {/* -- LIST -- */} { } const PreFetchingForm = ({ providerId, onSubmit }) => { - const { providerConfig } = useAuth() - const { getProvider, getProviderConnection } = useProviderApi() - const { data, fetchRequestAll, error } = useFetchAll() - const [provider, connection] = data ?? [] + const { data: config, error: errorConfig } = useGetProviderConfigQuery() + + const [getConnection, { data: connection, error: errorConnection }] = + useLazyGetProviderConnectionQuery() + const [getProvider, { data: provider, error: errorProvider }] = + useLazyGetProviderQuery() useEffect(() => { - providerId && - fetchRequestAll([ - getProvider(providerId), - getProviderConnection(providerId), - ]) + providerId && getProvider(providerId) + providerId && getConnection(providerId) }, []) - if (error) { + if (errorConfig || errorConnection || errorProvider) { return } - return providerId && !data ? ( + return providerId && (!config || !connection || !provider) ? ( ) : ( diff --git a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/index.js b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/index.js index 502387b576..505725ff06 100644 --- a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/index.js +++ b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/index.js @@ -14,8 +14,6 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useCallback } from 'react' - import FormWithSchema from 'client/components/Forms/FormWithSchema' import { T } from 'client/constants' @@ -31,11 +29,8 @@ const BasicConfiguration = () => ({ label: T.ProvisionOverview, resolver: () => STEP_FORM_SCHEMA, optionsValidate: { abortEarly: false }, - content: useCallback( - () => ( - - ), - [] + content: () => ( + ), }) diff --git a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/schema.js b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/schema.js index d0c2464b8f..0220479b2d 100644 --- a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/schema.js +++ b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/BasicConfiguration/schema.js @@ -13,30 +13,25 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import * as yup from 'yup' -import { INPUT_TYPES } from 'client/constants' +import { string, object } from 'yup' +import { T, INPUT_TYPES } from 'client/constants' import { getValidationFromFields } from 'client/utils' const NAME = { name: 'name', - label: 'Name', + label: T.Name, type: INPUT_TYPES.TEXT, - validation: yup - .string() - .min(1, 'Name field is required') - .trim() - .required('Name field is required') - .default(''), + validation: string().min(1).trim().required().default(''), } const DESCRIPTION = { name: 'description', - label: 'Description', + label: T.Description, type: INPUT_TYPES.TEXT, multiline: true, - validation: yup.string().trim().default(''), + validation: string().trim().default(''), } export const FORM_FIELDS = [NAME, DESCRIPTION] -export const STEP_FORM_SCHEMA = yup.object(getValidationFromFields(FORM_FIELDS)) +export const STEP_FORM_SCHEMA = object(getValidationFromFields(FORM_FIELDS)) diff --git a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Inputs/index.js b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Inputs/index.js index b5ffebd10c..7a557cb887 100644 --- a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Inputs/index.js +++ b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Inputs/index.js @@ -14,14 +14,13 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useCallback, useEffect, useState } from 'react' +import { useEffect, useState } from 'react' import { useFormContext } from 'react-hook-form' import { LinearProgress } from '@mui/material' -import { useFetch } from 'client/hooks' import { useGeneralApi } from 'client/features/General' -import { useProviderApi } from 'client/features/One' +import { useLazyGetProviderQuery } from 'client/features/OneApi/provider' import FormWithSchema from 'client/components/Forms/FormWithSchema' import { EmptyCard } from 'client/components/Cards' import { T } from 'client/constants' @@ -43,12 +42,11 @@ const Inputs = () => ({ label: T.ConfigureInputs, resolver: () => STEP_FORM_SCHEMA(inputs), optionsValidate: { abortEarly: false }, - content: useCallback(() => { + content: () => { const [fields, setFields] = useState(undefined) - const { changeLoading } = useGeneralApi() - const { getProvider } = useProviderApi() - const { data: fetchData, fetchRequest } = useFetch(getProvider) const { watch, reset } = useFormContext() + const { changeLoading } = useGeneralApi() + const [getProvider, { data: fetchData }] = useLazyGetProviderQuery() useEffect(() => { const { [PROVIDER_ID]: providerSelected = [], [STEP_ID]: currentInputs } = @@ -56,7 +54,7 @@ const Inputs = () => ({ if (!currentInputs) { changeLoading(true) // disable finish button until provider is fetched - fetchRequest(providerSelected[0]?.ID) + getProvider(providerSelected[0]?.ID) } else { setFields(FORM_FIELDS(inputs)) } @@ -92,7 +90,7 @@ const Inputs = () => ({ ) : ( ) - }, []), + }, }) export default Inputs diff --git a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/index.js b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/index.js index bf67e04782..64bafd40cd 100644 --- a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/index.js +++ b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/index.js @@ -14,12 +14,14 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useCallback, useMemo } from 'react' +import { useMemo } from 'react' import { useWatch } from 'react-hook-form' import { useListForm } from 'client/hooks' -import { useAuth } from 'client/features/Auth' -import { useProvider } from 'client/features/One' +import { + useGetProvidersQuery, + useGetProviderConfigQuery, +} from 'client/features/OneApi/provider' import { ListCards } from 'client/components/List' import { EmptyCard, ProvisionCard } from 'client/components/Cards' import { T } from 'client/constants' @@ -34,9 +36,9 @@ const Provider = () => ({ id: STEP_ID, label: T.Provider, resolver: () => STEP_FORM_SCHEMA, - content: useCallback(({ data, setFormData }) => { - const providers = useProvider() - const { providerConfig } = useAuth() + content: ({ data, setFormData }) => { + const { data: providers } = useGetProvidersQuery() + const { data: providerConfig } = useGetProviderConfigQuery() const provisionTemplateSelected = useWatch({ name: TEMPLATE_ID })?.[0] ?? {} @@ -87,7 +89,7 @@ const Provider = () => ({ }} /> ) - }, []), + }, }) export default Provider diff --git a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/schema.js b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/schema.js index 12989740aa..0abf6e1a96 100644 --- a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/schema.js +++ b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Provider/schema.js @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import * as yup from 'yup' +import { array, object } from 'yup' -export const STEP_FORM_SCHEMA = yup - .array(yup.object()) - .min(1, 'Select provider') - .max(1, 'Max. one provider selected') - .required('Provider field is required') +export const STEP_FORM_SCHEMA = array(object()) + .min(1) + .max(1) + .required() .default([]) diff --git a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Template/index.js b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Template/index.js index 9c491f021c..91a8e7d6fc 100644 --- a/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Template/index.js +++ b/src/fireedge/src/client/components/Forms/Provision/CreateForm/Steps/Template/index.js @@ -26,8 +26,11 @@ import { NavArrowRight } from 'iconoir-react' import { marked } from 'marked' import { useListForm } from 'client/hooks' -import { useAuth } from 'client/features/Auth' -import { useProvider, useProvisionTemplate } from 'client/features/One' +import { + useGetProvidersQuery, + useGetProviderConfigQuery, +} from 'client/features/OneApi/provider' +import { useGetProvisionTemplatesQuery } from 'client/features/OneApi/provision' import { ListCards } from 'client/components/List' import { ProvisionTemplateCard } from 'client/components/Cards' import { Step, sanitize } from 'client/utils' @@ -75,9 +78,9 @@ Description.propTypes = { description: PropTypes.string } // ---------------------------------------------------------- const Content = ({ data, setFormData }) => { - const providers = useProvider() - const provisionTemplates = useProvisionTemplate() - const { providerConfig } = useAuth() + const { data: provisionTemplates } = useGetProvisionTemplatesQuery() + const { data: providers } = useGetProvidersQuery() + const { data: providerConfig } = useGetProviderConfigQuery() const templateSelected = data?.[0] const provisionTypes = useMemo( @@ -177,7 +180,7 @@ const Content = ({ data, setFormData }) => { inputProps={{ 'data-cy': 'select-provision-type' }} labelId="select-provision-type-label" native - style={{ marginTop: '1em', minWidth: '8em' }} + sx={{ marginTop: '1em', minWidth: '8em' }} onChange={handleChangeProvision} value={provisionSelected} variant="outlined" @@ -198,7 +201,7 @@ const Content = ({ data, setFormData }) => { inputProps={{ 'data-cy': 'select-provider-type' }} labelId="select-provider-type-label" native - style={{ marginTop: '1em', minWidth: '8em' }} + sx={{ marginTop: '1em', minWidth: '8em' }} onChange={handleChangeProvider} value={providerSelected} variant="outlined" @@ -221,7 +224,7 @@ const Content = ({ data, setFormData }) => { [providerDescription] )} - + {/* -- LIST -- */} { - const { steps, defaultValues, resolver, transformBeforeSubmit } = Steps() + const stepsForm = useMemo(() => Steps(), []) + const { steps, defaultValues, resolver, transformBeforeSubmit } = stepsForm const methods = useForm({ mode: 'onSubmit', diff --git a/src/fireedge/src/client/components/Forms/Vm/AttachDiskForm/ImageSteps/ImagesTable/index.js b/src/fireedge/src/client/components/Forms/Vm/AttachDiskForm/ImageSteps/ImagesTable/index.js index 55d2b387b7..737cb85fde 100644 --- a/src/fireedge/src/client/components/Forms/Vm/AttachDiskForm/ImageSteps/ImagesTable/index.js +++ b/src/fireedge/src/client/components/Forms/Vm/AttachDiskForm/ImageSteps/ImagesTable/index.js @@ -44,7 +44,6 @@ const Content = ({ data, setFormData }) => { onlyGlobalSelectedRows initialState={{ selectedRowIds: { [ID]: true } }} onSelectedRowsChange={handleSelectedRows} - searchProps={{ 'data-cy': 'search-images' }} /> ) } diff --git a/src/fireedge/src/client/components/Forms/Vm/ChangeGroupForm/schema.js b/src/fireedge/src/client/components/Forms/Vm/ChangeGroupForm/schema.js index 326c3b4dad..9174f420c1 100644 --- a/src/fireedge/src/client/components/Forms/Vm/ChangeGroupForm/schema.js +++ b/src/fireedge/src/client/components/Forms/Vm/ChangeGroupForm/schema.js @@ -24,7 +24,7 @@ const GROUP = { name: 'group', label: 'Select the new group', type: INPUT_TYPES.TABLE, - Table: GroupsTable, + Table: () => GroupsTable, validation: string() .trim() .required('You must select a group') diff --git a/src/fireedge/src/client/components/Forms/Vm/ChangeUserForm/schema.js b/src/fireedge/src/client/components/Forms/Vm/ChangeUserForm/schema.js index a687d15b67..1bffb5363c 100644 --- a/src/fireedge/src/client/components/Forms/Vm/ChangeUserForm/schema.js +++ b/src/fireedge/src/client/components/Forms/Vm/ChangeUserForm/schema.js @@ -24,7 +24,7 @@ const USER = { name: 'user', label: 'Select the new owner', type: INPUT_TYPES.TABLE, - Table: UsersTable, + Table: () => UsersTable, validation: string() .trim() .required('You must select an user') diff --git a/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/fields.js b/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/fields.js index 52b7598f3e..f32e353d01 100644 --- a/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/fields.js +++ b/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/fields.js @@ -21,15 +21,15 @@ import { INPUT_TYPES, VM_ACTIONS_IN_CHARTER, VM_ACTIONS_WITH_SCHEDULE, + END_TYPE_VALUES, + REPEAT_VALUES, + ARGS_TYPES, + PERIOD_TYPES, } from 'client/constants' import { Field, sentenceCase, arrayToOptions } from 'client/utils' import { isRelative, - END_TYPE_VALUES, - REPEAT_VALUES, - ARGS_TYPES, getRequiredArgsByAction, - PERIOD_TYPES, getPeriodicityByTimeInSeconds, } from 'client/models/Scheduler' import { diff --git a/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/schema.js b/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/schema.js index a4bf602d07..24539a49ac 100644 --- a/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/schema.js +++ b/src/fireedge/src/client/components/Forms/Vm/CreateSchedActionForm/schema.js @@ -15,12 +15,13 @@ * ------------------------------------------------------------------------- */ import { string, object, ObjectSchema } from 'yup' -import { ARGS_TYPES, getRequiredArgsByAction } from 'client/models/Scheduler' +import { getRequiredArgsByAction } from 'client/models/Scheduler' import { Field, getObjectSchemaFromFields } from 'client/utils' import { PUNCTUAL_FIELDS, RELATIVE_FIELDS, } from 'client/components/Forms/Vm/CreateSchedActionForm/fields' +import { ARGS_TYPES } from 'client/constants' const { ACTION_FIELD } = PUNCTUAL_FIELDS diff --git a/src/fireedge/src/client/components/Forms/Vm/MigrateForm/Steps/AdvancedOptions/schema.js b/src/fireedge/src/client/components/Forms/Vm/MigrateForm/Steps/AdvancedOptions/schema.js index d3b22d6f14..be4648672a 100644 --- a/src/fireedge/src/client/components/Forms/Vm/MigrateForm/Steps/AdvancedOptions/schema.js +++ b/src/fireedge/src/client/components/Forms/Vm/MigrateForm/Steps/AdvancedOptions/schema.js @@ -35,7 +35,7 @@ const DATASTORE = { name: 'datastore', label: 'Select the new datastore', type: INPUT_TYPES.TABLE, - Table: DatastoresTable, + Table: () => DatastoresTable, validation: string() .trim() .notRequired() diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/bootSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/bootSchema.js index 42b73d6132..a65f3066ac 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/bootSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/bootSchema.js @@ -15,7 +15,7 @@ * ------------------------------------------------------------------------- */ import { string, boolean } from 'yup' -import { useHost } from 'client/features/One' +import { useGetHostsQuery } from 'client/features/OneApi/host' import { getKvmMachines, getKvmCpuModels } from 'client/models/Host' import { Field, arrayToOptions } from 'client/utils' import { @@ -64,7 +64,7 @@ export const MACHINE_TYPES = { notOnHypervisors: [vcenter, firecracker, lxc], type: INPUT_TYPES.SELECT, values: () => { - const hosts = useHost() + const { data: hosts = [] } = useGetHostsQuery() const kvmMachines = getKvmMachines(hosts) return arrayToOptions(kvmMachines) @@ -82,7 +82,7 @@ export const CPU_MODEL = { notOnHypervisors: [vcenter, firecracker, lxc], type: INPUT_TYPES.SELECT, values: () => { - const hosts = useHost() + const { data: hosts = [] } = useGetHostsQuery() const kvmCpuModels = getKvmCpuModels(hosts) return arrayToOptions(kvmCpuModels) diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/kernelSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/kernelSchema.js index 86b0ce015a..2f029e9571 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/kernelSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/kernelSchema.js @@ -15,7 +15,7 @@ * ------------------------------------------------------------------------- */ import { boolean, string } from 'yup' -import { useImage } from 'client/features/One' +import { useGetImagesQuery } from 'client/features/OneApi/image' import { getType } from 'client/models/Image' import { Field, clearNames } from 'client/utils' import { T, INPUT_TYPES, HYPERVISORS, IMAGE_TYPES_STR } from 'client/constants' @@ -47,7 +47,7 @@ export const KERNEL_DS = { dependOf: KERNEL_PATH_ENABLED.name, htmlType: (enabled) => enabled && INPUT_TYPES.HIDDEN, values: () => { - const images = useImage() + const { data: images = [] } = useGetImagesQuery() return images ?.filter((image) => getType(image) === IMAGE_TYPES_STR.KERNEL) diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/ramdiskSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/ramdiskSchema.js index 49c43ca501..391b01dc29 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/ramdiskSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/booting/ramdiskSchema.js @@ -15,7 +15,7 @@ * ------------------------------------------------------------------------- */ import { string, boolean } from 'yup' -import { useImage } from 'client/features/One' +import { useGetImagesQuery } from 'client/features/OneApi/image' import { getType } from 'client/models/Image' import { Field, clearNames } from 'client/utils' import { T, INPUT_TYPES, HYPERVISORS, IMAGE_TYPES_STR } from 'client/constants' @@ -47,7 +47,7 @@ export const RAMDISK_DS = { dependOf: RAMDISK_PATH_ENABLED.name, htmlType: (enabled) => enabled && INPUT_TYPES.HIDDEN, values: () => { - const images = useImage() + const { data: images = [] } = useGetImagesQuery() return images ?.filter((image) => getType(image) === IMAGE_TYPES_STR.RAMDISK) diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSchema.js index 4da3e9ca4b..56faff2711 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSchema.js @@ -15,7 +15,7 @@ * ------------------------------------------------------------------------- */ import { object, string, array, ObjectSchema } from 'yup' -import { useHost } from 'client/features/One' +import { useGetHostsQuery } from 'client/features/OneApi/host' import { getPciDevices } from 'client/models/Host' import { Field, @@ -46,7 +46,7 @@ const NAME_FIELD = { notOnHypervisors: [vcenter, lxc, firecracker], type: INPUT_TYPES.SELECT, values: () => { - const hosts = useHost() + const { data: hosts = [] } = useGetHostsQuery() const pciDevices = hosts.map(getPciDevices).flat() return arrayToOptions(pciDevices, { diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSection.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSection.js index ddc7c5b30a..45d041ec24 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSection.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/inputOutput/pciDevicesSection.js @@ -23,7 +23,7 @@ import { DeleteCircledOutline, AddCircledOutline } from 'iconoir-react' import { useFieldArray, useForm, FormProvider } from 'react-hook-form' import { yupResolver } from '@hookform/resolvers/yup' -import { useHost } from 'client/features/One' +import { useGetHostsQuery } from 'client/features/OneApi/host' import { FormWithSchema, Legend } from 'client/components/Forms' import { Translate } from 'client/components/HOC' import { getPciDevices } from 'client/models/Host' @@ -40,7 +40,7 @@ export const SECTION_ID = 'PCI' * @returns {JSXElementConstructor} - Inputs section */ const PciDevicesSection = ({ fields }) => { - const hosts = useHost() + const { data: hosts = [] } = useGetHostsQuery() const pciDevicesAvailable = useMemo( () => hosts.map(getPciDevices).flat(), [hosts.length] diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/numa/schema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/numa/schema.js index ebb73e4a7e..95ce5bc971 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/numa/schema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/numa/schema.js @@ -15,7 +15,7 @@ * ------------------------------------------------------------------------- */ import { string, number } from 'yup' -import { useHost } from 'client/features/One' +import { useGetHostsQuery } from 'client/features/OneApi/host' import { getHugepageSizes } from 'client/models/Host' import { T, @@ -144,7 +144,7 @@ const HUGEPAGES = { notOnHypervisors: [vcenter, firecracker], type: INPUT_TYPES.SELECT, values: () => { - const hosts = useHost() + const { data: hosts = [] } = useGetHostsQuery() const sizes = hosts .reduce((res, host) => res.concat(getHugepageSizes(host)), []) .flat() diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/scheduleAction.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/scheduleAction.js index 11fab28586..29cc13bfb9 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/scheduleAction.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/scheduleAction.js @@ -18,7 +18,12 @@ import { Calendar as ActionIcon } from 'iconoir-react' import { useFieldArray } from 'react-hook-form' import { ScheduleActionCard } from 'client/components/Cards' -import { CreateSchedButton, CharterButton } from 'client/components/Buttons' +import { + CreateSchedButton, + CharterButton, + UpdateSchedButton, + DeleteSchedButton, +} from 'client/components/Buttons/ScheduleAction' import { STEP_ID as EXTRA_ID, @@ -54,11 +59,11 @@ const ScheduleAction = () => { append(mappedActions) } - const handleUpdateAction = (action, index) => { + const handleUpdate = (action, index) => { update(index, mapNameFunction(action, index)) } - const handleRemoveAction = (index) => { + const handleRemove = (index) => { remove(index) } @@ -78,14 +83,26 @@ const ScheduleAction = () => { > {scheduleActions?.map((schedule, index) => { const { ID, NAME } = schedule + const fakeValues = { ...schedule, ID: index } return ( handleUpdateAction(newAction, index)} - handleRemove={() => handleRemoveAction(index)} + schedule={fakeValues} + actions={ + <> + handleUpdate(newAction, index)} + /> + handleRemove(index)} + /> + + } /> ) })} @@ -97,7 +114,7 @@ const ScheduleAction = () => { /** @type {TabType} */ const TAB = { id: 'sched_action', - name: T.ScheduledAction, + name: T.ScheduleAction, icon: ActionIcon, Content: ScheduleAction, getError: (error) => !!error?.[TAB_ID], diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema.js index 395cd0687b..040d8f2614 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/ExtraConfiguration/storage/schema.js @@ -15,7 +15,7 @@ * ------------------------------------------------------------------------- */ import { object, string, array, ObjectSchema } from 'yup' -import { useDatastore } from 'client/features/One' +import { useGetDatastoresQuery } from 'client/features/OneApi/datastore' import { getDeployMode } from 'client/models/Datastore' import { T, INPUT_TYPES } from 'client/constants' import { Field, arrayToOptions, getValidationFromFields } from 'client/utils' @@ -28,8 +28,8 @@ const TM_MAD_SYSTEM = { tooltip: T.DeployModeConcept, type: INPUT_TYPES.SELECT, values: () => { - const datastores = useDatastore() - const modes = datastores?.map(getDeployMode)?.flat() + const { data: datastores = [] } = useGetDatastoresQuery() + const modes = datastores.map(getDeployMode)?.flat() return arrayToOptions([...new Set(modes)], { addEmpty: 'Default' }) }, diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/ownershipSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/ownershipSchema.js index 288aedc9f9..2bb3b11f2c 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/ownershipSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/ownershipSchema.js @@ -15,7 +15,8 @@ * ------------------------------------------------------------------------- */ import { string } from 'yup' -import { useGroup, useUser } from 'client/features/One' +import { useGetUsersQuery } from 'client/features/OneApi/user' +import { useGetGroupsQuery } from 'client/features/OneApi/group' import { T, INPUT_TYPES } from 'client/constants' import { Field } from 'client/utils' @@ -25,7 +26,7 @@ export const UID_FIELD = { label: T.InstantiateAsUser, type: INPUT_TYPES.AUTOCOMPLETE, values: () => { - const users = useUser() + const { data: users = [] } = useGetUsersQuery() return users .map(({ ID: value, NAME: text }) => ({ text, value })) @@ -41,7 +42,7 @@ export const GID_FIELD = { label: T.InstantiateAsGroup, type: INPUT_TYPES.AUTOCOMPLETE, values: () => { - const groups = useGroup() + const { data: groups = [] } = useGetGroupsQuery() return groups .map(({ ID: value, NAME: text }) => ({ text, value })) diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/vmGroupSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/vmGroupSchema.js index 909c98edfb..0491997fdd 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/vmGroupSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/Steps/General/vmGroupSchema.js @@ -15,7 +15,7 @@ * ------------------------------------------------------------------------- */ import { string } from 'yup' -import { useVmGroup } from 'client/features/One' +import { useGetVMGroupsQuery } from 'client/features/OneApi/vmGroup' import { T, INPUT_TYPES } from 'client/constants' import { Field } from 'client/utils' @@ -25,7 +25,7 @@ export const VM_GROUP_FIELD = { label: T.AssociateToVMGroup, type: INPUT_TYPES.AUTOCOMPLETE, values: () => { - const vmGroups = useVmGroup() + const { data: vmGroups = [] } = useGetVMGroupsQuery() return vmGroups ?.map(({ ID, NAME }) => ({ text: `#${ID} ${NAME}`, value: String(ID) })) @@ -51,7 +51,7 @@ export const ROLE_FIELD = { htmlType: (vmGroup) => vmGroup && vmGroup !== '' ? undefined : INPUT_TYPES.HIDDEN, values: (vmGroupSelected) => { - const vmGroups = useVmGroup() + const { data: vmGroups = [] } = useGetVMGroupsQuery() const roles = vmGroups ?.filter(({ ID }) => ID === vmGroupSelected) diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js index c56422566e..4aaeebbfe8 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/CreateForm/index.js @@ -20,16 +20,13 @@ import PropTypes from 'prop-types' import { useForm, FormProvider } from 'react-hook-form' import { yupResolver } from '@hookform/resolvers/yup' -import { - useUserApi, - useVmGroupApi, - useVmTemplateApi, - useHostApi, - useImageApi, - useDatastoreApi, -} from 'client/features/One' +import { useGetVMGroupsQuery } from 'client/features/OneApi/vmGroup' +import { useGetHostsQuery } from 'client/features/OneApi/host' +import { useGetImagesQuery } from 'client/features/OneApi/image' +import { useGetUsersQuery } from 'client/features/OneApi/user' +import { useGetDatastoresQuery } from 'client/features/OneApi/datastore' +import { useLazyGetTemplateQuery } from 'client/features/OneApi/vmTemplate' -import { useFetch } from 'client/hooks' import FormStepper, { SkeletonStepsForm } from 'client/components/FormStepper' import Steps from 'client/components/Forms/VmTemplate/CreateForm/Steps' @@ -55,24 +52,15 @@ const CreateForm = ({ template, onSubmit }) => { } const PreFetchingForm = ({ templateId, onSubmit }) => { - const { getUsers } = useUserApi() - const { getVmGroups } = useVmGroupApi() - const { getHosts } = useHostApi() - const { getImages } = useImageApi() - const { getDatastores } = useDatastoreApi() - const { getVmTemplate } = useVmTemplateApi() - - const { fetchRequest, data } = useFetch(() => - getVmTemplate(templateId, { extended: true }) - ) + useGetVMGroupsQuery() + useGetHostsQuery() + useGetImagesQuery() + useGetUsersQuery() + useGetDatastoresQuery() + const [getTemplate, { data }] = useLazyGetTemplateQuery() useEffect(() => { - templateId && fetchRequest() - getHosts() - getImages() - getDatastores() - getUsers() - getVmGroups() + templateId && getTemplate({ id: templateId, extended: true }) }, []) return templateId && !data ? ( diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/ownershipSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/ownershipSchema.js index 96d748eefe..756705f305 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/ownershipSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/ownershipSchema.js @@ -16,7 +16,8 @@ /* eslint-disable jsdoc/require-jsdoc */ import { string } from 'yup' -import { useGroup, useUser } from 'client/features/One' +import { useGetUsersQuery } from 'client/features/OneApi/user' +import { useGetGroupsQuery } from 'client/features/OneApi/group' import { INPUT_TYPES } from 'client/constants' export const UID_FIELD = { @@ -24,7 +25,7 @@ export const UID_FIELD = { label: 'Instantiate as different User', type: INPUT_TYPES.AUTOCOMPLETE, values: () => { - const users = useUser() + const { data: users = [] } = useGetUsersQuery() return users .map(({ ID: value, NAME: text }) => ({ text, value })) @@ -39,7 +40,7 @@ export const GID_FIELD = { label: 'Instantiate as different Group', type: INPUT_TYPES.AUTOCOMPLETE, values: () => { - const groups = useGroup() + const { data: groups = [] } = useGetGroupsQuery() return groups .map(({ ID: value, NAME: text }) => ({ text, value })) diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/vmGroupSchema.js b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/vmGroupSchema.js index a90db4ad1a..e5c57a53f7 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/vmGroupSchema.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/BasicConfiguration/vmGroupSchema.js @@ -16,7 +16,7 @@ /* eslint-disable jsdoc/require-jsdoc */ import { string } from 'yup' -import { useVmGroup } from 'client/features/One' +import { useGetVMGroupsQuery } from 'client/features/OneApi/vmGroup' import { INPUT_TYPES } from 'client/constants' export const VM_GROUP_FIELD = { @@ -24,7 +24,7 @@ export const VM_GROUP_FIELD = { label: 'Associate VM to a VM Group', type: INPUT_TYPES.AUTOCOMPLETE, values: () => { - const vmGroups = useVmGroup() + const { data: vmGroups = [] } = useGetVMGroupsQuery() return vmGroups ?.map(({ ID, NAME }) => ({ text: `#${ID} ${NAME}`, value: String(ID) })) @@ -49,7 +49,7 @@ export const ROLE_FIELD = { htmlType: (vmGroup) => vmGroup && vmGroup !== '' ? undefined : INPUT_TYPES.HIDDEN, values: (vmGroupSelected) => { - const vmGroups = useVmGroup() + const { data: vmGroups = [] } = useGetVMGroupsQuery() const roles = vmGroups ?.filter(({ ID }) => ID === vmGroupSelected) diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/VmTemplatesTable/index.js b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/VmTemplatesTable/index.js index b467fb1e32..9fafa6c0f8 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/VmTemplatesTable/index.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/Steps/VmTemplatesTable/index.js @@ -18,7 +18,7 @@ import PropTypes from 'prop-types' import makeStyles from '@mui/styles/makeStyles' import { useListForm } from 'client/hooks' -import { useVmTemplateApi } from 'client/features/One' +import { useLazyGetTemplateQuery } from 'client/features/OneApi/vmTemplate' import { VmTemplatesTable } from 'client/components/Tables' import { SCHEMA } from 'client/components/Forms/VmTemplate/InstantiateForm/Steps/VmTemplatesTable/schema' @@ -39,7 +39,7 @@ const useStyles = makeStyles({ const Content = ({ data, setFormData }) => { const classes = useStyles() const selectedTemplate = data?.[0] - const { getVmTemplate } = useVmTemplateApi() + const [getVmTemplate] = useLazyGetTemplateQuery() const { handleSelect, handleClear } = useListForm({ key: STEP_ID, @@ -48,12 +48,12 @@ const Content = ({ data, setFormData }) => { const handleSelectedRows = async (rows) => { const { original: templateSelected } = rows?.[0] ?? {} - const { ID } = templateSelected ?? {} + const { ID: id } = templateSelected ?? {} - if (!ID) return handleClear() + if (!id) return handleClear() - const extendedTemplate = ID - ? await getVmTemplate(ID, { extended: true }) + const extendedTemplate = id + ? await getVmTemplate({ id, extended: true }).unwrap() : {} setFormData((prev) => ({ diff --git a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/index.js b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/index.js index 1e7f3dffd2..dce83b2f85 100644 --- a/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/index.js +++ b/src/fireedge/src/client/components/Forms/VmTemplate/InstantiateForm/index.js @@ -20,12 +20,9 @@ import PropTypes from 'prop-types' import { useForm, FormProvider } from 'react-hook-form' import { yupResolver } from '@hookform/resolvers/yup' -import { useFetch } from 'client/hooks' -import { - useUserApi, - useVmGroupApi, - useVmTemplateApi, -} from 'client/features/One' +import { useGetUsersQuery } from 'client/features/OneApi/user' +import { useGetGroupsQuery } from 'client/features/OneApi/group' +import { useLazyGetTemplateQuery } from 'client/features/OneApi/vmTemplate' import FormStepper, { SkeletonStepsForm } from 'client/components/FormStepper' import Steps from 'client/components/Forms/VmTemplate/InstantiateForm/Steps' @@ -53,17 +50,12 @@ const InstantiateForm = ({ template, onSubmit }) => { } const PreFetchingForm = ({ templateId, onSubmit }) => { - const { getUsers } = useUserApi() - const { getVmGroups } = useVmGroupApi() - const { getVmTemplate } = useVmTemplateApi() - const { fetchRequest, data } = useFetch(() => - getVmTemplate(templateId, { extended: true }) - ) + useGetUsersQuery() + useGetGroupsQuery() + const [getTemplate, { data }] = useLazyGetTemplateQuery() useEffect(() => { - templateId && fetchRequest() - getUsers() - getVmGroups() + templateId && getTemplate({ id: templateId, extended: true }) }, []) return templateId && !data ? ( diff --git a/src/fireedge/src/client/components/Header/Popover.js b/src/fireedge/src/client/components/Header/Popover.js index 9422bf5900..7cda82f23e 100644 --- a/src/fireedge/src/client/components/Header/Popover.js +++ b/src/fireedge/src/client/components/Header/Popover.js @@ -109,8 +109,7 @@ const HeaderPopover = memo( {(headerTitle || isMobile) && ( { const { view: currentView, views = {} } = useAuth() diff --git a/src/fireedge/src/client/components/Header/Zone.js b/src/fireedge/src/client/components/Header/Zone.js index 77465b0c7e..b5cc109ac4 100644 --- a/src/fireedge/src/client/components/Header/Zone.js +++ b/src/fireedge/src/client/components/Header/Zone.js @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useEffect, JSXElementConstructor } from 'react' +import { ReactElement } from 'react' import { MenuList, MenuItem, LinearProgress } from '@mui/material' import { Language as ZoneIcon } from 'iconoir-react' -import { useFetch } from 'client/hooks' -import { useZone, useZoneApi } from 'client/features/One' +import { useGetZonesQuery } from 'client/features/OneApi/zone' import HeaderPopover from 'client/components/Header/Popover' import { Translate } from 'client/components/HOC' import { T } from 'client/constants' @@ -27,12 +26,10 @@ import { T } from 'client/constants' /** * Menu to select the OpenNebula Zone. * - * @returns {JSXElementConstructor} Returns Zone list + * @returns {ReactElement} Returns Zone list */ const Zone = () => { - const zones = useZone() - const { getZones } = useZoneApi() - const { fetchRequest, loading } = useFetch(getZones) + const { data: zones = [], isLoading } = useGetZonesQuery() return ( { buttonProps={{ 'data-cy': 'header-zone-button' }} headerTitle={} > - {({ handleClose }) => { - useEffect(() => { - fetchRequest() - }, []) - - return ( - <> - {loading && } - - {zones?.length ? ( - zones?.map(({ ID, NAME }) => ( - - {NAME} - - )) - ) : ( - - + {({ handleClose }) => ( + <> + {isLoading && } + + {zones?.length ? ( + zones?.map(({ ID, NAME }) => ( + + {NAME} - )} - - - ) - }} + )) + ) : ( + + + + )} + + + )} ) } diff --git a/src/fireedge/src/client/components/List/ListInfiniteScroll.js b/src/fireedge/src/client/components/List/ListInfiniteScroll.js index 2ba032bbae..832dc0d430 100644 --- a/src/fireedge/src/client/components/List/ListInfiniteScroll.js +++ b/src/fireedge/src/client/components/List/ListInfiniteScroll.js @@ -64,7 +64,7 @@ const ListInfiniteScroll = ({ list, renderResult }) => { )}
diff --git a/src/fireedge/src/client/components/Tables/Clusters/index.js b/src/fireedge/src/client/components/Tables/Clusters/index.js index 1b6315e0fc..c2912eb046 100644 --- a/src/fireedge/src/client/components/Tables/Clusters/index.js +++ b/src/fireedge/src/client/components/Tables/Clusters/index.js @@ -13,46 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useMemo } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useCluster, useClusterApi } from 'client/features/One' +import { useGetClustersQuery } from 'client/features/OneApi/cluster' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import ClusterColumns from 'client/components/Tables/Clusters/columns' import ClusterRow from 'client/components/Tables/Clusters/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'clusters' + +/** + * @param {object} props - Props + * @returns {ReactElement} Clusters table + */ const ClustersTable = (props) => { - const columns = useMemo(() => ClusterColumns, []) + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` - const clusters = useCluster() - const { getClusters } = useClusterApi() - const { filterPool } = useAuth() + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetClustersQuery() - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getClusters) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (clusters?.length === 0 && [INIT, PENDING].includes(status)) { - return - } + const columns = useMemo( + () => + createColumns({ + filters: getResourceView(RESOURCE_NAMES.CLUSTER)?.filters, + columns: ClusterColumns, + }), + [view] + ) return ( String(row.ID)} RowComponent={ClusterRow} - {...props} + {...rest} /> ) } +ClustersTable.propTypes = { ...EnhancedTable.propTypes } +ClustersTable.displayName = 'ClustersTable' + export default ClustersTable diff --git a/src/fireedge/src/client/components/Tables/Datastores/index.js b/src/fireedge/src/client/components/Tables/Datastores/index.js index c21fd5f174..3f20b9d3b1 100644 --- a/src/fireedge/src/client/components/Tables/Datastores/index.js +++ b/src/fireedge/src/client/components/Tables/Datastores/index.js @@ -13,55 +13,60 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useMemo } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useDatastore, useDatastoreApi } from 'client/features/One' +import { useGetDatastoresQuery } from 'client/features/OneApi/datastore' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import DatastoreColumns from 'client/components/Tables/Datastores/columns' import DatastoreRow from 'client/components/Tables/Datastores/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'datastores' + +/** + * @param {object} props - Props + * @returns {ReactElement} Datastores table + */ const DatastoresTable = (props) => { - const { view, getResourceView, filterPool } = useAuth() + const { + rootProps = {}, + searchProps = {}, + useQuery = useGetDatastoresQuery, + ...rest + } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('DATASTORE')?.filters, + filters: getResourceView(RESOURCE_NAMES.DATASTORE)?.filters, columns: DatastoreColumns, }), [view] ) - const datastores = useDatastore() - const { getDatastores } = useDatastoreApi() - - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getDatastores) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (datastores?.length === 0 && [INIT, PENDING].includes(status)) { - return - } - return ( String(row.ID)} RowComponent={DatastoreRow} - {...props} + {...rest} /> ) } +DatastoresTable.propTypes = { ...EnhancedTable.propTypes } +DatastoresTable.displayName = 'DatastoresTable' + export default DatastoresTable diff --git a/src/fireedge/src/client/components/Tables/Datastores/row.js b/src/fireedge/src/client/components/Tables/Datastores/row.js index e61a20e2f1..55710ac841 100644 --- a/src/fireedge/src/client/components/Tables/Datastores/row.js +++ b/src/fireedge/src/client/components/Tables/Datastores/row.js @@ -13,71 +13,22 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { memo } from 'react' import PropTypes from 'prop-types' +import api from 'client/features/OneApi/datastore' +import { DatastoreCard } from 'client/components/Cards' -import { User, Group, Lock, Cloud, Server } from 'iconoir-react' -import { Typography } from '@mui/material' +const Row = memo( + ({ original, ...props }) => { + const state = api.endpoints.getDatastores.useQueryState(undefined, { + selectFromResult: ({ data = [] }) => + data.find((datastore) => +datastore.ID === +original.ID), + }) -import { - StatusCircle, - LinearProgressWithLabel, - StatusChip, -} from 'client/components/Status' -import { rowStyles } from 'client/components/Tables/styles' - -import * as DatastoreModel from 'client/models/Datastore' - -const Row = ({ original, value, ...props }) => { - const classes = rowStyles() - const { ID, NAME, UNAME, GNAME, TYPE, CLUSTERS, LOCK, PROVISION_ID } = value - - const { percentOfUsed, percentLabel } = DatastoreModel.getCapacityInfo(value) - - const { color: stateColor, name: stateName } = - DatastoreModel.getState(original) - - return ( -
-
- -
-
-
- {NAME} - - {LOCK && } - - -
-
- {`#${ID}`} - - - {` ${UNAME}`} - - - - {` ${GNAME}`} - - {PROVISION_ID && ( - - - {` ${PROVISION_ID}`} - - )} - - - {` ${CLUSTERS.join(',')}`} - -
-
-
- -
-
- ) -} + return + }, + (prev, next) => prev.className === next.className +) Row.propTypes = { original: PropTypes.object, @@ -86,4 +37,6 @@ Row.propTypes = { handleClick: PropTypes.func, } +Row.displayName = 'DatastoreRow' + export default Row diff --git a/src/fireedge/src/client/components/Tables/DockerHubTags/index.js b/src/fireedge/src/client/components/Tables/DockerHubTags/index.js index c55c08c4f9..27de813669 100644 --- a/src/fireedge/src/client/components/Tables/DockerHubTags/index.js +++ b/src/fireedge/src/client/components/Tables/DockerHubTags/index.js @@ -13,15 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect, useState, useCallback } from 'react' +import { useMemo, useEffect, useState, useCallback, ReactElement } from 'react' import PropTypes from 'prop-types' -import { useFetch } from 'client/hooks' -import { useMarketplaceAppApi } from 'client/features/One' +import { useLazyGetDockerHubTagsQuery } from 'client/features/OneApi/marketplaceApp' import EnhancedTable from 'client/components/Tables/Enhanced' import DockerHubTagsRow from 'client/components/Tables/DockerHubTags/row' +import { MarketplaceApp } from 'client/constants' + +const DEFAULT_DATA_CY = 'docker-tags' const getNextPageFromUrl = (url) => { try { @@ -33,49 +34,49 @@ const getNextPageFromUrl = (url) => { } } +/** + * @param {object} props - Props + * @param {MarketplaceApp} props.app - Marketplace App + * @returns {ReactElement} Datastores table + */ const DockerHubTagsTable = ({ app, ...props } = {}) => { - const { getDockerHubTags } = useMarketplaceAppApi() + const appId = app?.ID + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + const [tags, setTags] = useState(() => []) - - const { - data: { next, results = [] } = {}, - fetchRequest, - loading, - status, - STATUS: { INIT, FETCHED }, - } = useFetch(getDockerHubTags) + const [fetchRequest, { data: { next } = {}, isSuccess, isFetching }] = + useLazyGetDockerHubTagsQuery() useEffect(() => { - const appId = app?.ID - const requests = app?.ID && { - [INIT]: () => fetchRequest({ id: appId }), - [FETCHED]: () => { - if (!next) return + ;(async () => { + if (!appId || (isSuccess && !next)) return - const page = getNextPageFromUrl(next) - fetchRequest({ id: appId, page }) - }, - } - - requests[status]?.() - }, [app?.ID, status]) - - useEffect(() => { - status === FETCHED && setTags((prev) => prev.concat(results)) - }, [status]) + const page = next ? getNextPageFromUrl(next) : undefined + const { results = [] } = await fetchRequest({ id: appId, page }).unwrap() + setTags((prev) => prev.concat(results)) + })() + }, [appId, next]) const memoData = useMemo(() => tags, [tags?.length]) - const memoColumns = useMemo(() => [{ accessor: 'name' }], []) + if (!appId) { + return <>{'App ID is required'} + } + return ( String(row.name), [])} RowComponent={DockerHubTagsRow} - {...props} + {...rest} /> ) } diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js index 217cbbe77d..2e6f00a6f2 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/CategoryFilter.js @@ -27,7 +27,7 @@ import { import { Cancel } from 'iconoir-react' import { UseFiltersInstanceProps } from 'react-table' -import { Tr, Translate } from 'client/components/HOC' +import { Translate } from 'client/components/HOC' import { T } from 'client/constants' /** @@ -96,10 +96,9 @@ const CategoryFilter = ({ - {Tr(title)} + {isFiltered && ( }> diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalActions/Action.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalActions/Action.js index e54e7f4398..236498bec8 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalActions/Action.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalActions/Action.js @@ -13,10 +13,13 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, JSXElementConstructor } from 'react' +// eslint-disable-next-line no-unused-vars +import { memo, ReactElement } from 'react' import PropTypes from 'prop-types' +// eslint-disable-next-line no-unused-vars import { Row } from 'react-table' +import QueryButton from 'client/components/Buttons/QueryButton' import { Action } from 'client/components/Cards/SelectCard' import { ButtonToTriggerForm } from 'client/components/Forms' import { Tr } from 'client/components/HOC' @@ -29,7 +32,7 @@ import { CreateStepsCallback, CreateFormCallback } from 'client/utils' * @typedef {object} Option * @property {string} name - Label of option * @property {DialogProps} [dialogProps] - Dialog properties - * @property {JSXElementConstructor} [icon] - Icon + * @property {ReactElement} [icon] - Icon * @property {boolean} [isConfirmDialog] - If `true`, the form will be a dialog with confirmation buttons * @property {boolean|function(Row[]):boolean} [disabled] - If `true`, option will be disabled * @property {function(object, Row[])} onSubmit - Function to handle after finish the form @@ -48,18 +51,12 @@ import { CreateStepsCallback, CreateFormCallback } from 'client/utils' * @property {function(Row[])} [action] - Singular action without form * @property {boolean|{min: number, max: number}} [selected] - Condition for selected rows * @property {boolean|function(Row[]):boolean} [disabled] - If `true`, action will be disabled + * @property {function(Row[]):object} [useQuery] - Function to get rtk query result */ -/** - * Render global action. - * - * @param {object} props - Props - * @param {GlobalAction[]} props.item - Item action - * @param {Row[]} props.selectedRows - Selected rows - * @returns {JSXElementConstructor} Component JSX - */ const ActionItem = memo( ({ item, selectedRows }) => { + /** @type {GlobalAction} */ const { accessor, dataCy, @@ -71,6 +68,7 @@ const ActionItem = memo( options, action, disabled, + useQuery, } = item const buttonProps = { @@ -87,6 +85,8 @@ const ActionItem = memo( return action ? ( action?.(selectedRows)} /> + ) : useQuery ? ( + useQuery?.(selectedRows)} /> ) : ( { +const GlobalActions = ({ + disableRowSelect = false, + globalActions = [], + useTableProps, +}) => { /** @type {UseRowSelectInstanceProps} */ const { getToggleAllPageRowsSelectedProps, getToggleAllRowsSelectedProps } = useTableProps @@ -69,18 +74,20 @@ const GlobalActions = ({ globalActions = [], useTableProps }) => { ) return ( - - - + <> + {!disableRowSelect && ( + + )} {actionsNoSelected?.map((item) => ( ))} - {numberOfRowSelected > 0 && + {!disableRowSelect && + numberOfRowSelected > 0 && actionsSelected?.map((item, idx) => { const { min = 1, max = Number.MAX_SAFE_INTEGER } = item?.selected ?? {} @@ -92,15 +99,14 @@ const GlobalActions = ({ globalActions = [], useTableProps }) => { return })} - + ) } GlobalActions.propTypes = { - globalActions: PropTypes.arrayOf(ActionPropTypes), + globalActions: PropTypes.array, useTableProps: PropTypes.object, + disableRowSelect: PropTypes.bool, } -export { Action, ActionPropTypes } - export default GlobalActions diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js index f6470ba248..2529a225ef 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js @@ -79,9 +79,8 @@ const GlobalFilter = ({ useTableProps, className, searchProps }) => { const handleChange = useCallback( // Set undefined to remove the filter entirely - debounce((newFilter) => { - setGlobalFilter(newFilter || undefined) - }, 200) + debounce((newFilter) => setGlobalFilter(newFilter || undefined), 200), + [setGlobalFilter] ) return ( diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalSort.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalSort.js index 039d8bb1f7..4339375246 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalSort.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalSort.js @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ import { useEffect, useMemo, JSXElementConstructor } from 'react' import PropTypes from 'prop-types' @@ -44,8 +43,6 @@ const GlobalSort = ({ useTableProps }) => { /** @type {UseSortByState} */ const { sortBy } = state - useEffect(() => () => setSortBy([]), []) - const headersNotSorted = useMemo( () => headers.filter( @@ -66,7 +63,9 @@ const GlobalSort = ({ useTableProps }) => { setSortBy(sortBy.map((sort) => (sort.id === id ? { ...sort, desc } : sort))) } - return ( + useEffect(() => () => setSortBy([]), []) + + return !headersNotSorted.length && !sortBy.length ? null : ( {useMemo( () => ( diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/LabelFilter.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/LabelFilter.js index 7ae6d98b34..f970f3decc 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/Utils/LabelFilter.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/LabelFilter.js @@ -22,7 +22,7 @@ import { List, ListSubheader, IconButton } from '@mui/material' import { TreeView, TreeItem } from '@mui/lab' import { UseFiltersInstanceProps } from 'react-table' -import { Tr } from 'client/components/HOC' +import { Translate } from 'client/components/HOC' const buildTree = (data = [], separator = '/') => { const mapper = {} @@ -101,10 +101,9 @@ const LabelFilter = ({ title, column }) => { - {Tr(title)} + {isFiltered && ( { const styles = EnhancedTableStyles() - const isFetching = isLoading && data === undefined + const isUninitialized = isLoading && data === undefined const defaultColumn = useMemo( () => ({ @@ -140,7 +141,7 @@ const EnhancedTable = ({ const canNextPage = pageCount === -1 ? page.length >= pageSize : newPage < pageCount - 1 - newPage > pageIndex && canFetchMore && !canNextPage && fetchMore?.() + newPage > pageIndex && !canNextPage && fetchMore?.() } return ( @@ -151,13 +152,15 @@ const EnhancedTable = ({ >
{/* TOOLBAR */} - {!isFetching && ( - - )} + {/* PAGINATION */}
@@ -170,17 +173,9 @@ const EnhancedTable = ({
- {isLoading && ( - - )} -
{/* FILTERS */} - {!isFetching && ( + {!isUninitialized && ( {/* NO DATA MESSAGE */} - {!isFetching && page?.length === 0 && ( + {!isUninitialized && page?.length === 0 && ( @@ -219,8 +214,10 @@ const EnhancedTable = ({ value={values} className={isSelected ? 'selected' : ''} onClick={() => { - singleSelect && toggleAllRowsSelected(false) - toggleRowSelected(!isSelected) + if (!disableRowSelect) { + singleSelect && toggleAllRowsSelected?.(false) + toggleRowSelected?.(!isSelected) + } }} /> ) @@ -231,9 +228,9 @@ const EnhancedTable = ({ ) } -export const EnhancedTableProps = { +EnhancedTable.propTypes = { canFetchMore: PropTypes.bool, - globalActions: PropTypes.arrayOf(ActionPropTypes), + globalActions: PropTypes.array, columns: PropTypes.array, data: PropTypes.array, globalFilter: PropTypes.func, @@ -250,20 +247,19 @@ export const EnhancedTableProps = { searchProps: PropTypes.shape({ 'data-cy': PropTypes.string, }), + refetch: PropTypes.func, isLoading: PropTypes.bool, + disableGlobalSort: PropTypes.bool, + disableRowSelect: PropTypes.bool, onlyGlobalSearch: PropTypes.bool, onlyGlobalSelectedRows: PropTypes.bool, onSelectedRowsChange: PropTypes.func, pageSize: PropTypes.number, - RowComponent: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node, - PropTypes.func, - ]), + RowComponent: PropTypes.any, showPageCount: PropTypes.bool, singleSelect: PropTypes.bool, } -EnhancedTable.propTypes = EnhancedTableProps +export * from 'client/components/Tables/Enhanced/Utils' export default EnhancedTable diff --git a/src/fireedge/src/client/components/Tables/Enhanced/toolbar.js b/src/fireedge/src/client/components/Tables/Enhanced/toolbar.js index 94b9b004f7..d947bbe5f9 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/toolbar.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/toolbar.js @@ -18,66 +18,97 @@ import PropTypes from 'prop-types' import { Stack, useMediaQuery } from '@mui/material' import { UseTableInstanceProps, UseRowSelectState } from 'react-table' +import { RefreshDouble } from 'iconoir-react' import { GlobalActions, GlobalAction, - ActionPropTypes, GlobalSelectedRows, GlobalSort, } from 'client/components/Tables/Enhanced/Utils' +import { SubmitButton } from 'client/components/FormControl' +import { T } from 'client/constants' /** * @param {object} props - Props * @param {GlobalAction[]} props.globalActions - Global actions - * @param {object} props.onlyGlobalSelectedRows - Show only the selected rows + * @param {boolean} props.onlyGlobalSelectedRows - Show only the selected rows + * @param {boolean} props.disableRowSelect - Rows can't select + * @param {boolean} props.disableGlobalSort - Hide the sort filters * @param {UseTableInstanceProps} props.useTableProps - Table props + * @param {function():Promise} props.refetch - Function to refetch data + * @param {boolean} props.isLoading - The data is fetching * @returns {JSXElementConstructor} Returns table toolbar */ -const Toolbar = ({ globalActions, onlyGlobalSelectedRows, useTableProps }) => { - const isMobile = useMediaQuery((theme) => theme.breakpoints.down('sm')) +const Toolbar = ({ + globalActions, + onlyGlobalSelectedRows, + disableGlobalSort = false, + disableRowSelect = false, + useTableProps, + refetch, + isLoading, +}) => { const isSmallDevice = useMediaQuery((theme) => theme.breakpoints.down('md')) /** @type {UseRowSelectState} */ const { selectedRowIds } = useTableProps?.state ?? {} - if (onlyGlobalSelectedRows) { - return - } + const enableGlobalSort = !isSmallDevice && !disableGlobalSort + const enableGlobalSelect = + !onlyGlobalSelectedRows && !!Object.keys(selectedRowIds).length - return isMobile ? null : ( + return ( <> - - - - - {!isSmallDevice && ( -
- -
+ + {refetch && ( + } + title={T.Tooltip} + isSubmitting={isLoading} + onClick={refetch} + /> )} - {!!Object.keys(selectedRowIds).length && ( - + {onlyGlobalSelectedRows && !disableRowSelect ? ( + + ) : ( + )} + {(enableGlobalSort || enableGlobalSelect) && ( + + {enableGlobalSort && } + {enableGlobalSelect && ( + + )} + + )} ) } Toolbar.propTypes = { - globalActions: PropTypes.arrayOf(ActionPropTypes), + globalActions: PropTypes.array, onlyGlobalSelectedRows: PropTypes.bool, + disableRowSelect: PropTypes.bool, + disableGlobalSort: PropTypes.bool, useTableProps: PropTypes.object, + refetch: PropTypes.func, + isLoading: PropTypes.bool, } export default Toolbar diff --git a/src/fireedge/src/client/components/Tables/Groups/index.js b/src/fireedge/src/client/components/Tables/Groups/index.js index b89653a0b1..7e0eb803ce 100644 --- a/src/fireedge/src/client/components/Tables/Groups/index.js +++ b/src/fireedge/src/client/components/Tables/Groups/index.js @@ -13,55 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useGroup, useGroupApi } from 'client/features/One' +import { useGetGroupsQuery } from 'client/features/OneApi/group' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import GroupColumns from 'client/components/Tables/Groups/columns' import GroupRow from 'client/components/Tables/Groups/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'groups' + +/** + * @param {object} props - Props + * @returns {ReactElement} Groups table + */ const GroupsTable = (props) => { - const { view, getResourceView, filterPool } = useAuth() + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetGroupsQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('GROUP')?.filters, + filters: getResourceView(RESOURCE_NAMES.GROUP)?.filters, columns: GroupColumns, }), [view] ) - const groups = useGroup() - const { getGroups } = useGroupApi() - - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getGroups) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (groups?.length === 0 && [INIT, PENDING].includes(status)) { - return - } - return ( String(row.ID)} RowComponent={GroupRow} - {...props} + {...rest} /> ) } +GroupsTable.propTypes = { ...EnhancedTable.propTypes } +GroupsTable.displayName = 'GroupsTable' + export default GroupsTable diff --git a/src/fireedge/src/client/components/Tables/Hosts/index.js b/src/fireedge/src/client/components/Tables/Hosts/index.js index 048fdd45fc..d0c0d3b26e 100644 --- a/src/fireedge/src/client/components/Tables/Hosts/index.js +++ b/src/fireedge/src/client/components/Tables/Hosts/index.js @@ -13,62 +13,60 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useHost, useHostApi } from 'client/features/One' +import { useGetHostsQuery } from 'client/features/OneApi/host' -import { - SkeletonTable, - EnhancedTable, - EnhancedTableProps, -} from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import HostColumns from 'client/components/Tables/Hosts/columns' import HostRow from 'client/components/Tables/Hosts/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'hosts' + +/** + * @param {object} props - Props + * @returns {ReactElement} Hosts table + */ const HostsTable = (props) => { - const { view, getResourceView, filterPool } = useAuth() + const { + rootProps = {}, + searchProps = {}, + useQuery = useGetHostsQuery, + ...rest + } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('HOST')?.filters, + filters: getResourceView(RESOURCE_NAMES.HOST)?.filters, columns: HostColumns, }), [view] ) - const hosts = useHost() - const { getHosts } = useHostApi() - - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getHosts) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (hosts?.length === 0 && [INIT, PENDING].includes(status)) { - return - } - return ( String(row.ID)} RowComponent={HostRow} - {...props} + {...rest} /> ) } -HostsTable.propTypes = EnhancedTableProps +HostsTable.propTypes = { ...EnhancedTable.propTypes } HostsTable.displayName = 'HostsTable' export default HostsTable diff --git a/src/fireedge/src/client/components/Tables/Hosts/row.js b/src/fireedge/src/client/components/Tables/Hosts/row.js index 209794aab2..617ed5f549 100644 --- a/src/fireedge/src/client/components/Tables/Hosts/row.js +++ b/src/fireedge/src/client/components/Tables/Hosts/row.js @@ -13,86 +13,22 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { memo } from 'react' import PropTypes from 'prop-types' +import hostApi from 'client/features/OneApi/host' +import { HostCard } from 'client/components/Cards' -import { Server, ModernTv } from 'iconoir-react' -import { Typography } from '@mui/material' +const Row = memo( + ({ original, ...props }) => { + const state = hostApi.endpoints.getHosts.useQueryState(undefined, { + selectFromResult: ({ data = [] }) => + data.find((host) => +host.ID === +original.ID), + }) -import { - StatusCircle, - LinearProgressWithLabel, - StatusChip, -} from 'client/components/Status' -import { rowStyles } from 'client/components/Tables/styles' -import { Tr } from 'client/components/HOC' - -import * as HostModel from 'client/models/Host' -import { T } from 'client/constants' - -const Row = ({ original, value, ...props }) => { - const classes = rowStyles() - const { - ID, - NAME, - IM_MAD, - VM_MAD, - RUNNING_VMS, - TOTAL_VMS, - CLUSTER, - TEMPLATE, - } = value - - const { percentCpuUsed, percentCpuLabel, percentMemUsed, percentMemLabel } = - HostModel.getAllocatedInfo(value) - - const { color: stateColor, name: stateName } = HostModel.getState(original) - - const labels = [...new Set([IM_MAD, VM_MAD])] - - return ( -
-
- -
-
-
- - {TEMPLATE?.NAME ?? NAME} - - - {labels.map((label) => ( - - ))} - -
-
- {`#${ID}`} - - - {` ${CLUSTER}`} - - - - {` ${RUNNING_VMS} / ${TOTAL_VMS}`} - -
-
-
- - -
-
- ) -} + return + }, + (prev, next) => prev.className === next.className +) Row.propTypes = { original: PropTypes.object, @@ -101,4 +37,6 @@ Row.propTypes = { handleClick: PropTypes.func, } +Row.displayName = 'HostRow' + export default Row diff --git a/src/fireedge/src/client/components/Tables/Images/detail.js b/src/fireedge/src/client/components/Tables/Images/detail.js deleted file mode 100644 index 1a060e0bc6..0000000000 --- a/src/fireedge/src/client/components/Tables/Images/detail.js +++ /dev/null @@ -1,108 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useEffect } from 'react' -import PropTypes from 'prop-types' -import { LinearProgress } from '@mui/material' - -import Tabs from 'client/components/Tabs' -import { StatusBadge } from 'client/components/Status' - -import { useFetch, useSocket } from 'client/hooks' -import { useImageApi } from 'client/features/One' - -import { prettyBytes } from 'client/utils' -import * as ImageModel from 'client/models/Image' -import * as Helper from 'client/models/Helper' - -const ImageDetail = ({ id }) => { - const { getImage } = useImageApi() - - const { getHooksSocket } = useSocket() - const socket = getHooksSocket({ resource: 'image', id }) - - const { data, fetchRequest, loading, error } = useFetch(getImage, socket) - const isLoading = (!data && !error) || loading - - useEffect(() => { - fetchRequest(id) - }, [id]) - - if (isLoading) { - return - } - - if (error) { - return
{error}
- } - - const { - ID, - NAME, - UNAME, - GNAME, - REGTIME, - SIZE, - PERSISTENT, - LOCK, - DATASTORE, - VMS, - RUNNING_VMS, - } = data - - const { name: stateName, color: stateColor } = ImageModel.getState(data) - const type = ImageModel.getType(data) - const size = +SIZE ? prettyBytes(+SIZE, 'MB') : '-' - - const usedByVms = [VMS?.ID ?? []].flat().length || 0 - - const tabs = [ - { - name: 'info', - renderContent: ( -
-
- - {`#${ID} - ${NAME}`} -
-
-

Owner: {UNAME}

-

Group: {GNAME}

-

Datastore: {DATASTORE}

-

Persistent: {type}

-

Size: {size}

-

Register time: {Helper.timeToString(REGTIME)}

-

Locked: {Helper.levelLockToString(LOCK?.LOCKED)}

-

Persistent: {Helper.booleanToString(PERSISTENT)}

-

Running VMS: {` ${RUNNING_VMS} / ${usedByVms}`}

-
-
- ), - }, - ] - - return -} - -ImageDetail.propTypes = { - id: PropTypes.string.isRequired, -} - -export default ImageDetail diff --git a/src/fireedge/src/client/components/Tables/Images/index.js b/src/fireedge/src/client/components/Tables/Images/index.js index acd5651663..c21c187721 100644 --- a/src/fireedge/src/client/components/Tables/Images/index.js +++ b/src/fireedge/src/client/components/Tables/Images/index.js @@ -13,53 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useImage, useImageApi } from 'client/features/One' +import { useGetImagesQuery } from 'client/features/OneApi/image' -import { - SkeletonTable, - EnhancedTable, - EnhancedTableProps, -} from 'client/components/Tables' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import ImageColumns from 'client/components/Tables/Images/columns' import ImageRow from 'client/components/Tables/Images/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'images' + +/** + * @param {object} props - Props + * @returns {ReactElement} Images table + */ const ImagesTable = (props) => { - const columns = useMemo(() => ImageColumns, []) + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` - const images = useImage() - const { getImages } = useImageApi() - const { filterPool } = useAuth() + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetImagesQuery() - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getImages) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (images?.length === 0 && [INIT, PENDING].includes(status)) { - return - } + const columns = useMemo( + () => + createColumns({ + filters: getResourceView(RESOURCE_NAMES.IMAGE)?.filters, + columns: ImageColumns, + }), + [view] + ) return ( String(row.ID)} RowComponent={ImageRow} - {...props} + {...rest} /> ) } -ImagesTable.propTypes = EnhancedTableProps +ImagesTable.propTypes = { ...EnhancedTable.propTypes } ImagesTable.displayName = 'ImagesTable' export default ImagesTable diff --git a/src/fireedge/src/client/components/Tables/MarketplaceApps/actions.js b/src/fireedge/src/client/components/Tables/MarketplaceApps/actions.js index 1660913499..2188e75c9b 100644 --- a/src/fireedge/src/client/components/Tables/MarketplaceApps/actions.js +++ b/src/fireedge/src/client/components/Tables/MarketplaceApps/actions.js @@ -16,18 +16,17 @@ /* eslint-disable jsdoc/require-jsdoc */ import { useMemo } from 'react' import { useHistory } from 'react-router-dom' -import { RefreshDouble, AddSquare, CloudDownload } from 'iconoir-react' +import { AddSquare, CloudDownload } from 'iconoir-react' import { useAuth } from 'client/features/Auth' import { useGeneralApi } from 'client/features/General' -import { useMarketplaceAppApi } from 'client/features/One' import { Translate } from 'client/components/HOC' +import { useExportAppMutation } from 'client/features/OneApi/marketplaceApp' import { ExportForm } from 'client/components/Forms/MarketplaceApp' - import { createActions } from 'client/components/Tables/Enhanced/Utils' import { PATH } from 'client/apps/sunstone/routesOne' -import { T, MARKETPLACE_APP_ACTIONS } from 'client/constants' +import { T, RESOURCE_NAMES, MARKETPLACE_APP_ACTIONS } from 'client/constants' const MessageToConfirmAction = (rows) => { const names = rows?.map?.(({ original }) => original?.NAME) @@ -51,21 +50,13 @@ const Actions = () => { const history = useHistory() const { view, getResourceView } = useAuth() const { enqueueSuccess } = useGeneralApi() - const { getMarketplaceApps, exportApp } = useMarketplaceAppApi() + const [exportApp] = useExportAppMutation() const marketplaceAppActions = useMemo( () => createActions({ - filters: getResourceView('MARKETPLACE-APP')?.actions, + filters: getResourceView(RESOURCE_NAMES.APP)?.actions, actions: [ - { - accessor: MARKETPLACE_APP_ACTIONS.REFRESH, - tooltip: T.Refresh, - icon: RefreshDouble, - action: async () => { - await getMarketplaceApps() - }, - }, { accessor: MARKETPLACE_APP_ACTIONS.CREATE_DIALOG, tooltip: T.CreateMarketApp, @@ -88,9 +79,9 @@ const Actions = () => { return ExportForm(app, app) }, onSubmit: async (formData, rows) => { - const appId = rows?.[0]?.original?.ID - const response = await exportApp(appId, formData) - enqueueSuccess(response) + const id = rows?.[0]?.original?.ID + const res = await exportApp({ id, ...formData }).unwrap() + enqueueSuccess(res) }, }, ], diff --git a/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js b/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js index b34f1fe5e0..48dd57167d 100644 --- a/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js +++ b/src/fireedge/src/client/components/Tables/MarketplaceApps/index.js @@ -13,55 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useMarketplaceApp, useMarketplaceAppApi } from 'client/features/One' +import { useGetMarketplaceAppsQuery } from 'client/features/OneApi/marketplaceApp' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import MarketplaceAppColumns from 'client/components/Tables/MarketplaceApps/columns' import MarketplaceAppRow from 'client/components/Tables/MarketplaceApps/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'apps' + +/** + * @param {object} props - Props + * @returns {ReactElement} Marketplace Apps table + */ const MarketplaceAppsTable = (props) => { - const { view, getResourceView, filterPool } = useAuth() + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetMarketplaceAppsQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('MARKETPLACE-APP')?.filters, + filters: getResourceView(RESOURCE_NAMES.APP)?.filters, columns: MarketplaceAppColumns, }), [view] ) - const marketplaceApps = useMarketplaceApp() - const { getMarketplaceApps } = useMarketplaceAppApi() - - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getMarketplaceApps) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (marketplaceApps?.length === 0 && [INIT, PENDING].includes(status)) { - return - } - return ( String(row.ID)} RowComponent={MarketplaceAppRow} - {...props} + {...rest} /> ) } +MarketplaceAppsTable.propTypes = { ...EnhancedTable.propTypes } +MarketplaceAppsTable.displayName = 'MarketplaceAppsTable' + export default MarketplaceAppsTable diff --git a/src/fireedge/src/client/components/Tables/Marketplaces/index.js b/src/fireedge/src/client/components/Tables/Marketplaces/index.js index 6a9cd5579c..cb1f8b0b43 100644 --- a/src/fireedge/src/client/components/Tables/Marketplaces/index.js +++ b/src/fireedge/src/client/components/Tables/Marketplaces/index.js @@ -13,58 +13,52 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import PropTypes from 'prop-types' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useMarketplace, useMarketplaceApi } from 'client/features/One' +import { useGetMarketplacesQuery } from 'client/features/OneApi/marketplace' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import MarketplaceColumns from 'client/components/Tables/Marketplaces/columns' import MarketplaceRow from 'client/components/Tables/Marketplaces/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'marketplaces' + +/** + * @param {object} props - Props + * @param {function():Array} [props.filter] - Function to filter the data + * @returns {ReactElement} Marketplaces table + */ const MarketplacesTable = ({ filter, ...props }) => { - const { view, getResourceView, filterPool } = useAuth() + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetMarketplacesQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('MARKETPLACE')?.filters, + filters: getResourceView(RESOURCE_NAMES.MARKETPLACE)?.filters, columns: MarketplaceColumns, }), [view] ) - const marketplaces = useMarketplace() - const { getMarketplaces } = useMarketplaceApi() - - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getMarketplaces) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (marketplaces?.length === 0 && [INIT, PENDING].includes(status)) { - return - } - return ( String(row.ID)} RowComponent={MarketplaceRow} - {...props} + {...rest} /> ) } @@ -73,7 +67,6 @@ MarketplacesTable.propTypes = { filter: PropTypes.func, ...EnhancedTable.propTypes, } - MarketplacesTable.displayName = 'MarketplacesTable' export default MarketplacesTable diff --git a/src/fireedge/src/client/components/Tables/Skeleton/index.js b/src/fireedge/src/client/components/Tables/Skeleton/index.js index 2f620dd5a8..6944988ecd 100644 --- a/src/fireedge/src/client/components/Tables/Skeleton/index.js +++ b/src/fireedge/src/client/components/Tables/Skeleton/index.js @@ -39,7 +39,7 @@ const SkeletonTable = memo(() => { const rowClasses = rowStyles() const SkeletonRow = () => ( - +
@@ -67,18 +67,10 @@ const SkeletonTable = memo(() => {
{isMobile ? ( - + ) : ( - - + +
diff --git a/src/fireedge/src/client/components/Tables/Users/index.js b/src/fireedge/src/client/components/Tables/Users/index.js index 30956590be..23b1f62e08 100644 --- a/src/fireedge/src/client/components/Tables/Users/index.js +++ b/src/fireedge/src/client/components/Tables/Users/index.js @@ -13,55 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useUser, useUserApi } from 'client/features/One' +import { useGetUsersQuery } from 'client/features/OneApi/user' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import UserColumns from 'client/components/Tables/Users/columns' import UserRow from 'client/components/Tables/Users/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'users' + +/** + * @param {object} props - Props + * @returns {ReactElement} Users table + */ const UsersTable = (props) => { - const { view, getResourceView, filterPool } = useAuth() + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetUsersQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('USER')?.filters, + filters: getResourceView(RESOURCE_NAMES.USER)?.filters, columns: UserColumns, }), [view] ) - const users = useUser() - const { getUsers } = useUserApi() - - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getUsers) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (users?.length === 0 && [INIT, PENDING].includes(status)) { - return - } - return ( String(row.ID)} RowComponent={UserRow} - {...props} + {...rest} /> ) } +UsersTable.propTypes = { ...EnhancedTable.propTypes } +UsersTable.displayName = 'UsersTable' + export default UsersTable diff --git a/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js b/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js index 44f1b1c92c..8c264635d5 100644 --- a/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js +++ b/src/fireedge/src/client/components/Tables/VNetworkTemplates/index.js @@ -13,46 +13,56 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' -import { useFetch } from 'client/hooks' -import { - useVNetworkTemplate, - useVNetworkTemplateApi, -} from 'client/features/One' +import { useMemo, ReactElement } from 'react' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' +import { useAuth } from 'client/features/Auth' +import { useGetVNTemplatesQuery } from 'client/features/OneApi/networkTemplate' + +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import VNetworkTemplateColumns from 'client/components/Tables/VNetworkTemplates/columns' import VNetworkTemplateRow from 'client/components/Tables/VNetworkTemplates/row' +import { RESOURCE_NAMES } from 'client/constants' -const VNetworkTemplatesTable = () => { - const columns = useMemo(() => VNetworkTemplateColumns, []) +const DEFAULT_DATA_CY = 'vnet-templates' - const vNetworkTemplates = useVNetworkTemplate() - const { getVNetworkTemplates } = useVNetworkTemplateApi() +/** + * @param {object} props - Props + * @returns {ReactElement} Virtual Network Templates table + */ +const VNetworkTemplatesTable = (props) => { + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getVNetworkTemplates) - const { INIT, PENDING } = STATUS + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetVNTemplatesQuery() - useEffect(() => { - fetchRequest() - }, []) - - if (vNetworkTemplates?.length === 0 && [INIT, PENDING].includes(status)) { - return - } + const columns = useMemo( + () => + createColumns({ + filters: getResourceView(RESOURCE_NAMES.VN_TEMPLATE)?.filters, + columns: VNetworkTemplateColumns, + }), + [view] + ) return ( String(row.ID)} RowComponent={VNetworkTemplateRow} + {...rest} /> ) } +VNetworkTemplatesTable.propTypes = { ...EnhancedTable.propTypes } +VNetworkTemplatesTable.displayName = 'VNetworkTemplatesTable' + export default VNetworkTemplatesTable diff --git a/src/fireedge/src/client/components/Tables/VNetworks/index.js b/src/fireedge/src/client/components/Tables/VNetworks/index.js index fb5ec87fef..69a791fe86 100644 --- a/src/fireedge/src/client/components/Tables/VNetworks/index.js +++ b/src/fireedge/src/client/components/Tables/VNetworks/index.js @@ -13,51 +13,60 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' -import { useFetch } from 'client/hooks' -import { useVNetwork, useVNetworkApi } from 'client/features/One' +import { useAuth } from 'client/features/Auth' +import { useGetVNetworksQuery } from 'client/features/OneApi/network' -import { - SkeletonTable, - EnhancedTable, - EnhancedTableProps, -} from 'client/components/Tables' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import VNetworkColumns from 'client/components/Tables/VNetworks/columns' import VNetworkRow from 'client/components/Tables/VNetworks/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'vnets' + +/** + * @param {object} props - Props + * @returns {ReactElement} Virtual networks table + */ const VNetworksTable = (props) => { - const columns = useMemo(() => VNetworkColumns, []) + const { + rootProps = {}, + searchProps = {}, + useQuery = useGetVNetworksQuery, + ...rest + } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` - const vNetworks = useVNetwork() - const { getVNetworks } = useVNetworkApi() + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useQuery() - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getVNetworks) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, []) - - if (vNetworks?.length === 0 && [INIT, PENDING].includes(status)) { - return - } + const columns = useMemo( + () => + createColumns({ + filters: getResourceView(RESOURCE_NAMES.VNET)?.filters, + columns: VNetworkColumns, + }), + [view] + ) return ( String(row.ID)} RowComponent={VNetworkRow} - {...props} + {...rest} /> ) } -VNetworksTable.propTypes = EnhancedTableProps -VNetworksTable.displayName = 'VNetworksTable' +VNetworksTable.propTypes = { ...EnhancedTable.propTypes } +VNetworksTable.displayName = 'VirtualNetworksTable' export default VNetworksTable diff --git a/src/fireedge/src/client/components/Tables/VNetworks/row.js b/src/fireedge/src/client/components/Tables/VNetworks/row.js index 1e416e50ea..ae7c8e0e17 100644 --- a/src/fireedge/src/client/components/Tables/VNetworks/row.js +++ b/src/fireedge/src/client/components/Tables/VNetworks/row.js @@ -13,73 +13,22 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { memo } from 'react' import PropTypes from 'prop-types' +import api from 'client/features/OneApi/network' +import { NetworkCard } from 'client/components/Cards' -import { User, Group, Lock, Server, Cloud } from 'iconoir-react' -import { Typography } from '@mui/material' +const Row = memo( + ({ original, ...props }) => { + const state = api.endpoints.getVNetworks.useQueryState(undefined, { + selectFromResult: ({ data = [] }) => + data.find((network) => +network.ID === +original.ID), + }) -import { LinearProgressWithLabel } from 'client/components/Status' -import { rowStyles } from 'client/components/Tables/styles' - -import * as VirtualNetworkModel from 'client/models/VirtualNetwork' - -const Row = ({ original, value, ...props }) => { - const classes = rowStyles() - const { - ID, - NAME, - UNAME, - GNAME, - LOCK, - CLUSTERS, - USED_LEASES, - TOTAL_LEASES, - PROVISION_ID, - } = value - - const { percentOfUsed, percentLabel } = - VirtualNetworkModel.getLeasesInfo(original) - - return ( -
-
-
- {NAME} - {LOCK && } -
-
- {`#${ID}`} - - - {` ${UNAME}`} - - - - {` ${GNAME}`} - - - - {` ${CLUSTERS}`} - - {PROVISION_ID && ( - - - {` ${PROVISION_ID}`} - - )} -
-
-
- -
-
- ) -} + return + }, + (prev, next) => prev.className === next.className +) Row.propTypes = { original: PropTypes.object, @@ -88,4 +37,6 @@ Row.propTypes = { handleClick: PropTypes.func, } +Row.displayName = 'VirtualNetworkRow' + export default Row diff --git a/src/fireedge/src/client/components/Tables/VRouters/index.js b/src/fireedge/src/client/components/Tables/VRouters/index.js index 4f8800a577..64e82ba2a3 100644 --- a/src/fireedge/src/client/components/Tables/VRouters/index.js +++ b/src/fireedge/src/client/components/Tables/VRouters/index.js @@ -13,43 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' -import { useFetch } from 'client/hooks' -import { useVRouter, useVRouterApi } from 'client/features/One' +import { useAuth } from 'client/features/Auth' +import { useGetVRoutersQuery } from 'client/features/OneApi/vrouter' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import VRouterColumns from 'client/components/Tables/VRouters/columns' import VRouterRow from 'client/components/Tables/VRouters/row' +import { RESOURCE_NAMES } from 'client/constants' -const VRoutersTable = () => { - const columns = useMemo(() => VRouterColumns, []) +const DEFAULT_DATA_CY = 'vrouters' - const vRouters = useVRouter() - const { getVRouters } = useVRouterApi() +/** + * @param {object} props - Props + * @returns {ReactElement} Virtual Routers table + */ +const VRoutersTable = (props) => { + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getVRouters) - const { INIT, PENDING } = STATUS + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetVRoutersQuery() - useEffect(() => { - fetchRequest() - }, []) - - if (vRouters?.length === 0 && [INIT, PENDING].includes(status)) { - return - } + const columns = useMemo( + () => + createColumns({ + filters: getResourceView(RESOURCE_NAMES.V_ROUTER)?.filters, + columns: VRouterColumns, + }), + [view] + ) return ( String(row.ID)} RowComponent={VRouterRow} + {...rest} /> ) } +VRoutersTable.propTypes = { ...EnhancedTable.propTypes } +VRoutersTable.displayName = 'VRoutersTable' + export default VRoutersTable diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/actions.js b/src/fireedge/src/client/components/Tables/VmTemplates/actions.js index 4743bb66fd..646c1c4850 100644 --- a/src/fireedge/src/client/components/Tables/VmTemplates/actions.js +++ b/src/fireedge/src/client/components/Tables/VmTemplates/actions.js @@ -17,7 +17,6 @@ import { useMemo } from 'react' import { useHistory } from 'react-router-dom' import { - RefreshDouble, AddSquare, Import, Trash, @@ -28,7 +27,12 @@ import { } from 'iconoir-react' import { useAuth } from 'client/features/Auth' -import { useVmTemplateApi } from 'client/features/One' +import { + useLockTemplateMutation, + useUnlockTemplateMutation, + useCloneTemplateMutation, + useRemoveTemplateMutation, +} from 'client/features/OneApi/vmTemplate' import { Tr, Translate } from 'client/components/HOC' import { CloneForm } from 'client/components/Forms/VmTemplate' @@ -63,22 +67,16 @@ MessageToConfirmAction.displayName = 'MessageToConfirmAction' const Actions = () => { const history = useHistory() const { view, getResourceView } = useAuth() - const { getVmTemplate, getVmTemplates, lock, unlock, clone, remove } = - useVmTemplateApi() + const [lock] = useLockTemplateMutation() + const [unlock] = useUnlockTemplateMutation() + const [clone] = useCloneTemplateMutation() + const [remove] = useRemoveTemplateMutation() const vmTemplateActions = useMemo( () => createActions({ - filters: getResourceView('VM-TEMPLATE')?.actions, + filters: getResourceView(RESOURCE_NAMES.VM_TEMPLATE)?.actions, actions: [ - { - accessor: VM_TEMPLATE_ACTIONS.REFRESH, - tooltip: T.Refresh, - icon: RefreshDouble, - action: async () => { - await getVmTemplates() - }, - }, { accessor: VM_TEMPLATE_ACTIONS.CREATE_DIALOG, tooltip: T.Create, @@ -169,26 +167,18 @@ const Actions = () => { return CloneForm(stepProps, initialValues) }, onSubmit: async (formData, rows) => { - try { - const { prefix } = formData + const { prefix, ...restOfData } = formData - const vmTemplates = rows?.map?.( - ({ original: { ID, NAME } = {} }) => { - // overwrite all names with prefix+NAME - const formatData = prefix - ? { name: `${prefix} ${NAME}` } - : {} + const vmTemplates = rows?.map?.( + ({ original: { ID, NAME } = {} }) => { + // overwrite all names with prefix+NAME + const name = prefix ? `${prefix} ${NAME}` : NAME - return { id: ID, data: { ...formData, ...formatData } } - } - ) + return { id: ID, ...restOfData, name } + } + ) - await Promise.all( - vmTemplates.map(({ id, data }) => clone(id, data)) - ) - } finally { - await getVmTemplates() - } + await Promise.all(vmTemplates.map(clone)) }, }, ], @@ -245,8 +235,7 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => lock(id))) - await Promise.all(ids.map((id) => getVmTemplate(id))) + await Promise.all(ids.map((id) => lock({ id }))) }, }, { @@ -260,7 +249,6 @@ const Actions = () => { onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) await Promise.all(ids.map((id) => unlock(id))) - await Promise.all(ids.map((id) => getVmTemplate(id))) }, }, ], @@ -280,8 +268,7 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => remove(id))) - await getVmTemplates() + await Promise.all(ids.map((id) => remove({ id }))) }, }, ], diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/index.js b/src/fireedge/src/client/components/Tables/VmTemplates/index.js index 16c20f01e5..ab4abf9b1e 100644 --- a/src/fireedge/src/client/components/Tables/VmTemplates/index.js +++ b/src/fireedge/src/client/components/Tables/VmTemplates/index.js @@ -13,62 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useVmTemplate, useVmTemplateApi } from 'client/features/One' +import { useGetTemplatesQuery } from 'client/features/OneApi/vmTemplate' -import { - SkeletonTable, - EnhancedTable, - EnhancedTableProps, -} from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import VmTemplateColumns from 'client/components/Tables/VmTemplates/columns' import VmTemplateRow from 'client/components/Tables/VmTemplates/row' +import { RESOURCE_NAMES } from 'client/constants' +const DEFAULT_DATA_CY = 'vm-templates' + +/** + * @param {object} props - Props + * @returns {ReactElement} VM Templates table + */ const VmTemplatesTable = (props) => { - const { view, getResourceView, filterPool } = useAuth() + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetTemplatesQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('VM-TEMPLATE')?.filters, + filters: getResourceView(RESOURCE_NAMES.VM_TEMPLATE)?.filters, columns: VmTemplateColumns, }), [view] ) - const vmTemplates = useVmTemplate() - const { getVmTemplates } = useVmTemplateApi() - - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getVmTemplates) - const { INIT, PENDING } = STATUS - - useEffect(() => { - fetchRequest() - }, [filterPool]) - - if (vmTemplates?.length === 0 && [INIT, PENDING].includes(status)) { - return - } - return ( String(row.ID)} RowComponent={VmTemplateRow} - {...props} + {...rest} /> ) } -VmTemplatesTable.propTypes = EnhancedTableProps +VmTemplatesTable.propTypes = { ...EnhancedTable.propTypes } VmTemplatesTable.displayName = 'VmTemplatesTable' export default VmTemplatesTable diff --git a/src/fireedge/src/client/components/Tables/VmTemplates/row.js b/src/fireedge/src/client/components/Tables/VmTemplates/row.js index 0391ae1bfa..37433e98e2 100644 --- a/src/fireedge/src/client/components/Tables/VmTemplates/row.js +++ b/src/fireedge/src/client/components/Tables/VmTemplates/row.js @@ -13,76 +13,34 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo } from 'react' +import { memo } from 'react' import PropTypes from 'prop-types' +import vmTemplateApi from 'client/features/OneApi/vmTemplate' +import { VmTemplateCard } from 'client/components/Cards' -import { User, Group, Lock } from 'iconoir-react' -import { Typography } from '@mui/material' +const Row = memo( + ({ original, ...props }) => { + const state = vmTemplateApi.endpoints.getTemplates.useQueryState( + undefined, + { + selectFromResult: ({ data = [] }) => + data.find((template) => +template.ID === +original.ID), + } + ) -import { StatusChip } from 'client/components/Status' -import { rowStyles } from 'client/components/Tables/styles' -import Image from 'client/components/Image' - -import * as Helper from 'client/models/Helper' -import { isExternalURL } from 'client/utils' -import { LOGO_IMAGES_URL } from 'client/constants' - -const Row = ({ original, value, ...props }) => { - const classes = rowStyles() - const { ID, NAME, UNAME, GNAME, REGTIME, LOCK, VROUTER, LOGO = '' } = value - - const [logoSource] = useMemo(() => { - const external = isExternalURL(LOGO) - const cleanLogoAttribute = String(LOGO).split('/').at(-1) - const src = external ? LOGO : `${LOGO_IMAGES_URL}/${cleanLogoAttribute}` - - return [src, external] - }, [LOGO]) - - const time = Helper.timeFromMilliseconds(+REGTIME) - const timeAgo = `registered ${time.toRelative()}` - - return ( -
-
- logo -
-
-
- {NAME} - - {LOCK && } - {VROUTER && } - -
-
- - {`#${ID} ${timeAgo}`} - - - - {` ${UNAME}`} - - - - {` ${GNAME}`} - -
-
-
- ) -} + return + }, + (prev, next) => prev.className === next.className +) Row.propTypes = { original: PropTypes.object, value: PropTypes.object, isSelected: PropTypes.bool, + className: PropTypes.string, handleClick: PropTypes.func, } +Row.displayName = 'VmTemplateRow' + export default Row diff --git a/src/fireedge/src/client/components/Tables/Vms/actions.js b/src/fireedge/src/client/components/Tables/Vms/actions.js index f2910bbafe..c272cd06b3 100644 --- a/src/fireedge/src/client/components/Tables/Vms/actions.js +++ b/src/fireedge/src/client/components/Tables/Vms/actions.js @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ import { useMemo } from 'react' import { useHistory } from 'react-router-dom' import { Typography } from '@mui/material' import { - RefreshDouble, AddSquare, PlayOutline, SaveFloppyDisk, @@ -32,7 +30,17 @@ import { import { useAuth } from 'client/features/Auth' import { useGeneralApi } from 'client/features/General' -import { useDatastore, useVmApi } from 'client/features/One' +import { useGetDatastoresQuery } from 'client/features/OneApi/datastore' +import { + useLockVmMutation, + useUnlockVmMutation, + useSaveAsTemplateMutation, + useDeployMutation, + useActionVmMutation, + useMigrateMutation, + useChangeVmOwnershipMutation, + useRecoverMutation, +} from 'client/features/OneApi/vm' import { Translate } from 'client/components/HOC' import { @@ -42,8 +50,11 @@ import { MigrateForm, SaveAsTemplateForm, } from 'client/components/Forms/Vm' +import { + createActions, + GlobalAction, +} from 'client/components/Tables/Enhanced/Utils' -import { createActions } from 'client/components/Tables/Enhanced/Utils' import { PATH } from 'client/apps/sunstone/routesOne' import { getLastHistory, isAvailableAction } from 'client/models/VirtualMachine' import { T, VM_ACTIONS, RESOURCE_NAMES } from 'client/constants' @@ -52,7 +63,7 @@ const isDisabled = (action) => (rows) => isAvailableAction(action)(rows, ({ values }) => values?.STATE) const ListVmNames = ({ rows = [] }) => { - const datastores = useDatastore() + const { data: datastores = [] } = useGetDatastoresQuery() return rows?.map?.(({ id, original }) => { const { ID, NAME } = original @@ -88,52 +99,30 @@ const MessageToConfirmAction = (rows) => ( ) +/** + * Generates the actions to operate resources on VM table. + * + * @returns {GlobalAction} - Actions + */ const Actions = () => { const history = useHistory() const { view, getResourceView } = useAuth() const { enqueueSuccess } = useGeneralApi() - const { - getVm, - getVms, - saveAsTemplate, - terminate, - terminateHard, - undeploy, - undeployHard, - poweroff, - poweroffHard, - reboot, - rebootHard, - hold, - release, - stop, - suspend, - resume, - resched, - unresched, - recover, - changeOwnership, - deploy, - migrate, - migrateLive, - lock, - unlock, - } = useVmApi() + + const [saveAsTemplate] = useSaveAsTemplateMutation() + const [actionVm] = useActionVmMutation() + const [recover] = useRecoverMutation() + const [changeOwnership] = useChangeVmOwnershipMutation() + const [deploy] = useDeployMutation() + const [migrate] = useMigrateMutation() + const [lock] = useLockVmMutation() + const [unlock] = useUnlockVmMutation() const vmActions = useMemo( () => createActions({ - filters: getResourceView('VM')?.actions, + filters: getResourceView(RESOURCE_NAMES.VM)?.actions, actions: [ - { - accessor: VM_ACTIONS.REFRESH, - dataCy: `vm_${VM_ACTIONS.REFRESH}`, - tooltip: T.Refresh, - icon: RefreshDouble, - action: async () => { - await getVms({ state: -1 }) - }, - }, { accessor: VM_ACTIONS.CREATE_DIALOG, dataCy: `vm_${VM_ACTIONS.CREATE_DIALOG}`, @@ -154,8 +143,9 @@ const Actions = () => { icon: PlayOutline, action: async (rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => resume(id))) - ids?.length > 1 && (await Promise.all(ids.map((id) => getVm(id)))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'resume' })) + ) }, }, { @@ -187,8 +177,8 @@ const Actions = () => { }, form: SaveAsTemplateForm, onSubmit: async (formData, rows) => { - const vmId = rows?.[0]?.original?.ID - const response = await saveAsTemplate(vmId, formData) + const data = { id: rows?.[0]?.original?.ID, ...formData } + const response = await saveAsTemplate(data) enqueueSuccess(response) }, }, @@ -213,8 +203,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => suspend(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'suspend' })) + ) }, }, { @@ -229,8 +220,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => stop(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'stop' })) + ) }, }, { @@ -245,8 +237,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => poweroff(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'poweroff' })) + ) }, }, { @@ -261,8 +254,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => poweroffHard(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'poweroff-hard' })) + ) }, }, { @@ -277,8 +271,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => reboot(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'reboot' })) + ) }, }, { @@ -293,8 +288,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => rebootHard(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'reboot-hard' })) + ) }, }, { @@ -309,8 +305,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => undeploy(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'undeploy' })) + ) }, }, { @@ -325,8 +322,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => undeployHard(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'undeploy-hard' })) + ) }, }, ], @@ -350,8 +348,9 @@ const Actions = () => { }, onSubmit: async (formData, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => deploy(id, formData))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => deploy({ id, ...formData })) + ) }, }, { @@ -366,8 +365,9 @@ const Actions = () => { }, onSubmit: async (formData, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => migrate(id, formData))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => migrate({ id, ...formData })) + ) }, }, { @@ -382,8 +382,9 @@ const Actions = () => { }, onSubmit: async (formData, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => migrateLive(id, formData))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => migrate({ id, ...formData, live: true })) + ) }, }, { @@ -398,8 +399,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => hold(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'hold' })) + ) }, }, { @@ -414,8 +416,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => release(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'release' })) + ) }, }, { @@ -430,8 +433,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => resched(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'resched' })) + ) }, }, { @@ -446,8 +450,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => unresched(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'unresched' })) + ) }, }, { @@ -460,11 +465,11 @@ const Actions = () => { dataCy: `modal-${VM_ACTIONS.RECOVER}`, }, form: RecoverForm, - onSubmit: async (_, rows) => { + onSubmit: async (formData, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => recover(id))) - ids?.length > 1 && - (await Promise.all(ids.map((id) => getVm(id)))) + await Promise.all( + ids.map((id) => recover({ id, ...formData })) + ) }, }, ], @@ -489,9 +494,8 @@ const Actions = () => { onSubmit: async (newOwnership, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) await Promise.all( - ids.map((id) => changeOwnership(id, newOwnership)) + ids.map((id) => changeOwnership({ id, ...newOwnership })) ) - await Promise.all(ids.map((id) => getVm(id))) }, }, { @@ -507,9 +511,8 @@ const Actions = () => { onSubmit: async (newOwnership, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) await Promise.all( - ids.map((id) => changeOwnership(id, newOwnership)) + ids.map((id) => changeOwnership({ id, ...newOwnership })) ) - await Promise.all(ids.map((id) => getVm(id))) }, }, ], @@ -533,8 +536,7 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => lock(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all(ids.map((id) => lock({ id }))) }, }, { @@ -550,7 +552,6 @@ const Actions = () => { onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) await Promise.all(ids.map((id) => unlock(id))) - await Promise.all(ids.map((id) => getVm(id))) }, }, ], @@ -574,8 +575,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => terminate(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'terminate' })) + ) }, }, { @@ -590,8 +592,9 @@ const Actions = () => { }, onSubmit: async (_, rows) => { const ids = rows?.map?.(({ original }) => original?.ID) - await Promise.all(ids.map((id) => terminateHard(id))) - await Promise.all(ids.map((id) => getVm(id))) + await Promise.all( + ids.map((id) => actionVm({ id, action: 'terminate-hard' })) + ) }, }, ], diff --git a/src/fireedge/src/client/components/Tables/Vms/index.js b/src/fireedge/src/client/components/Tables/Vms/index.js index 6f503b6110..ebb4b03a4b 100644 --- a/src/fireedge/src/client/components/Tables/Vms/index.js +++ b/src/fireedge/src/client/components/Tables/Vms/index.js @@ -13,85 +13,74 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' import { useAuth } from 'client/features/Auth' -import { useFetch } from 'client/hooks' -import { useVm, useVmApi } from 'client/features/One' +import { useGetVmsQuery } from 'client/features/OneApi/vm' -import { - SkeletonTable, - EnhancedTable, - EnhancedTableProps, -} from 'client/components/Tables' -import { createColumns } from 'client/components/Tables/Enhanced/Utils' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import VmColumns from 'client/components/Tables/Vms/columns' import VmRow from 'client/components/Tables/Vms/row' +import { RESOURCE_NAMES } from 'client/constants' -const INITIAL_ELEMENT = 0 -const INTERVAL_ON_FIRST_RENDER = 2_000 +// const INITIAL_ELEMENT = 0 +// const INTERVAL_ON_FIRST_RENDER = 2_000 +// const INITIAL_ARGS = { +// start: INITIAL_ELEMENT, +// end: -INTERVAL_ON_FIRST_RENDER, +// state: -1, +// } + +const DEFAULT_DATA_CY = 'vms' + +/** + * @param {object} props - Props + * @returns {ReactElement} Virtual Machines table + */ const VmsTable = (props) => { - const vms = useVm() - const { getVms } = useVmApi() - const { view, getResourceView, filterPool } = useAuth() + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` + + const { view, getResourceView } = useAuth() + // const [args, setArgs] = useState(() => INITIAL_ARGS) + const { data = [], isFetching, refetch } = useGetVmsQuery() const columns = useMemo( () => createColumns({ - filters: getResourceView('VM')?.filters, + filters: getResourceView(RESOURCE_NAMES.VM)?.filters, columns: VmColumns, }), [view] ) - const { status, data, fetchRequest, loading, reloading, error, STATUS } = - useFetch(getVms) - const { INIT, PENDING, FETCHED } = STATUS + /* useEffect(() => { + const lastVmId = data[INTERVAL_ON_FIRST_RENDER - 1]?.ID + const end = isSuccess ? lastVmId : -INTERVAL_ON_FIRST_RENDER - useEffect(() => { - const requests = { - [INIT]: () => - fetchRequest({ - start: INITIAL_ELEMENT, - end: -INTERVAL_ON_FIRST_RENDER, - state: -1, // Any state, except DONE - }), - [FETCHED]: () => { - const canFetchMore = - !error && data?.vms?.length === INTERVAL_ON_FIRST_RENDER - - // fetch the rest of VMs, from 0 to last VM ID fetched - canFetchMore && - fetchRequest({ - start: INITIAL_ELEMENT, - end: data?.vms[INTERVAL_ON_FIRST_RENDER - 1]?.ID, - state: -1, // Any state, except DONE - }) - }, + if (isSuccess && data?.length === INTERVAL_ON_FIRST_RENDER) { + setArgs({ start: INITIAL_ELEMENT, end, state: -1 }) } - - requests[status]?.() - }, [filterPool, status, data]) - - if (vms?.length === 0 && [INIT, PENDING].includes(status)) { - return - } + }, [isSuccess]) */ return ( String(row.ID)} RowComponent={VmRow} - {...props} + {...rest} /> ) } -VmsTable.propTypes = EnhancedTableProps +VmsTable.propTypes = { ...EnhancedTable.propTypes } VmsTable.displayName = 'VmsTable' export default VmsTable diff --git a/src/fireedge/src/client/components/Tables/Vms/row.js b/src/fireedge/src/client/components/Tables/Vms/row.js index 0bd4923e95..0ee5f50fe4 100644 --- a/src/fireedge/src/client/components/Tables/Vms/row.js +++ b/src/fireedge/src/client/components/Tables/Vms/row.js @@ -13,85 +13,31 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { memo } from 'react' import PropTypes from 'prop-types' +import vmApi from 'client/features/OneApi/vm' +import { VirtualMachineCard } from 'client/components/Cards' -import { User, Group, Lock, HardDrive } from 'iconoir-react' -import { Stack, Typography } from '@mui/material' +const Row = memo( + ({ original, ...props }) => { + const state = vmApi.endpoints.getVms.useQueryState(undefined, { + selectFromResult: ({ data = [] }) => + data.find((vm) => +vm.ID === +original.ID), + }) -import { StatusCircle } from 'client/components/Status' -import MultipleTags from 'client/components/MultipleTags' -import { rowStyles } from 'client/components/Tables/styles' - -import * as VirtualMachineModel from 'client/models/VirtualMachine' -import * as Helper from 'client/models/Helper' - -const Row = ({ original, value, ...props }) => { - const classes = rowStyles() - const { - ID, - NAME, - UNAME, - GNAME, - IPS, - STIME, - ETIME, - HOSTNAME = '--', - LOCK, - } = value - - const time = Helper.timeFromMilliseconds(+ETIME || +STIME) - const timeAgo = `${+ETIME ? 'done' : 'started'} ${time.toRelative()}` - - const { color: stateColor, name: stateName } = - VirtualMachineModel.getState(original) - - return ( -
-
- -
-
-
- - {NAME} - - - {LOCK && } - -
-
- {`#${ID} ${timeAgo}`} - - - {` ${UNAME}`} - - - - {` ${GNAME}`} - - - - {` ${HOSTNAME}`} - -
-
- {!!IPS?.length && ( -
- - - -
- )} -
- ) -} + return + }, + (prev, next) => prev.className === next.className +) Row.propTypes = { original: PropTypes.object, value: PropTypes.object, isSelected: PropTypes.bool, + className: PropTypes.string, handleClick: PropTypes.func, } +Row.displayName = 'VirtualMachineRow' + export default Row diff --git a/src/fireedge/src/client/components/Tables/Zones/index.js b/src/fireedge/src/client/components/Tables/Zones/index.js index 3a7039df63..93035d7723 100644 --- a/src/fireedge/src/client/components/Tables/Zones/index.js +++ b/src/fireedge/src/client/components/Tables/Zones/index.js @@ -13,43 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo, useEffect } from 'react' +import { useMemo, ReactElement } from 'react' -import { useFetch } from 'client/hooks' -import { useZone, useZoneApi } from 'client/features/One' +import { useAuth } from 'client/features/Auth' +import { useGetZonesQuery } from 'client/features/OneApi/zone' -import { SkeletonTable, EnhancedTable } from 'client/components/Tables' +import EnhancedTable, { createColumns } from 'client/components/Tables/Enhanced' import ZoneColumns from 'client/components/Tables/Zones/columns' import ZoneRow from 'client/components/Tables/Zones/row' +import { RESOURCE_NAMES } from 'client/constants' -const ZonesTable = () => { - const columns = useMemo(() => ZoneColumns, []) +const DEFAULT_DATA_CY = 'zones' - const zones = useZone() - const { getZones } = useZoneApi() +/** + * @param {object} props - Props + * @returns {ReactElement} Zones table + */ +const ZonesTable = (props) => { + const { rootProps = {}, searchProps = {}, ...rest } = props ?? {} + rootProps['data-cy'] ??= DEFAULT_DATA_CY + searchProps['data-cy'] ??= `search-${DEFAULT_DATA_CY}` - const { status, fetchRequest, loading, reloading, STATUS } = - useFetch(getZones) - const { INIT, PENDING } = STATUS + const { view, getResourceView } = useAuth() + const { data = [], isFetching, refetch } = useGetZonesQuery() - useEffect(() => { - fetchRequest() - }, []) - - if (zones?.length === 0 && [INIT, PENDING].includes(status)) { - return - } + const columns = useMemo( + () => + createColumns({ + filters: getResourceView(RESOURCE_NAMES.ZONE)?.filters, + columns: ZoneColumns, + }), + [view] + ) return ( String(row.ID)} RowComponent={ZoneRow} + {...rest} /> ) } +ZonesTable.propTypes = { ...EnhancedTable.propTypes } +ZonesTable.displayName = 'ZonesTable' + export default ZonesTable diff --git a/src/fireedge/src/client/components/Tables/index.js b/src/fireedge/src/client/components/Tables/index.js index 9f8f637faf..ebf00fc087 100644 --- a/src/fireedge/src/client/components/Tables/index.js +++ b/src/fireedge/src/client/components/Tables/index.js @@ -16,9 +16,7 @@ import ClustersTable from 'client/components/Tables/Clusters' import DatastoresTable from 'client/components/Tables/Datastores' import DockerHubTagsTable from 'client/components/Tables/DockerHubTags' -import EnhancedTable, { - EnhancedTableProps, -} from 'client/components/Tables/Enhanced' +import EnhancedTable from 'client/components/Tables/Enhanced' import GroupsTable from 'client/components/Tables/Groups' import HostsTable from 'client/components/Tables/Hosts' import ImagesTable from 'client/components/Tables/Images' @@ -37,7 +35,6 @@ import ZonesTable from 'client/components/Tables/Zones' export { SkeletonTable, EnhancedTable, - EnhancedTableProps, VirtualizedTable, ClustersTable, DatastoresTable, diff --git a/src/fireedge/src/client/components/Tabs/Cluster/Info/index.js b/src/fireedge/src/client/components/Tabs/Cluster/Info/index.js index b2b9722aa6..e3faa53a18 100644 --- a/src/fireedge/src/client/components/Tabs/Cluster/Info/index.js +++ b/src/fireedge/src/client/components/Tabs/Cluster/Info/index.js @@ -13,53 +13,60 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext } from 'react' +import { ReactElement, useCallback } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useClusterApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useGetClusterQuery, + useUpdateClusterMutation, +} from 'client/features/OneApi/cluster' import { AttributePanel } from 'client/components/Tabs/Common' import Information from 'client/components/Tabs/Cluster/Info/information' import { Tr } from 'client/components/HOC' import { T } from 'client/constants' -import * as Helper from 'client/models/Helper' +import { + jsonToXml, + getActionsAvailable, + filterAttributes, +} from 'client/models/Helper' import { cloneObject, set } from 'client/utils' const HIDDEN_ATTRIBUTES_REG = /^(HOST|RESERVED_CPU|RESERVED_MEM)$/ -const ClusterInfoTab = ({ tabProps = {} }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Cluster id + * @returns {ReactElement} Information tab + */ +const ClusterInfoTab = ({ tabProps = {}, id }) => { const { information_panel: informationPanel, attributes_panel: attributesPanel, } = tabProps - const { rename, update } = useClusterApi() - const { handleRefetch, data: cluster = {} } = useContext(TabContext) - const { ID, TEMPLATE } = cluster - - const handleRename = async (newName) => { - const response = await rename(ID, newName) - String(response) === String(ID) && (await handleRefetch?.()) - } + const [update] = useUpdateClusterMutation() + const { data: cluster } = useGetClusterQuery({ id }) + const { TEMPLATE } = cluster const handleAttributeInXml = async (path, newValue) => { const newTemplate = cloneObject(TEMPLATE) - set(newTemplate, path, newValue) - const xml = Helper.jsonToXml(newTemplate) - - // 0: Replace the whole template - const response = await update(ID, xml, 0) - - String(response) === String(ID) && (await handleRefetch?.()) + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) } - const getActions = (actions) => Helper.getActionsAvailable(actions) + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) - const { attributes } = Helper.filterAttributes(TEMPLATE, { + const { attributes } = filterAttributes(TEMPLATE, { hidden: HIDDEN_ATTRIBUTES_REG, }) @@ -70,19 +77,16 @@ const ClusterInfoTab = ({ tabProps = {} }) => { } return ( -
{informationPanel?.enabled && ( )} {attributesPanel?.enabled && ( @@ -93,12 +97,13 @@ const ClusterInfoTab = ({ tabProps = {} }) => { title={Tr(T.Attributes)} /> )} -
+ ) } ClusterInfoTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } ClusterInfoTab.displayName = 'ClusterInfoTab' diff --git a/src/fireedge/src/client/components/Tabs/Cluster/Info/information.js b/src/fireedge/src/client/components/Tabs/Cluster/Info/information.js index e126460a84..4ce0e9ca4b 100644 --- a/src/fireedge/src/client/components/Tabs/Cluster/Info/information.js +++ b/src/fireedge/src/client/components/Tabs/Cluster/Info/information.js @@ -13,24 +13,38 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' +import { useRenameClusterMutation } from 'client/features/OneApi/cluster' import { List } from 'client/components/Tabs/Common' +import { T, Cluster, CLUSTER_ACTIONS } from 'client/constants' -import { T, CLUSTER_ACTIONS } from 'client/constants' - -const InformationPanel = ({ cluster = {}, handleRename, actions }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {Cluster} props.cluster - Cluster resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ cluster = {}, actions }) => { + const [renameCluster] = useRenameClusterMutation() const { ID, NAME, TEMPLATE } = cluster const { RESERVED_MEM, RESERVED_CPU } = TEMPLATE + const handleRename = async (_, newName) => { + await renameCluster({ id: ID, name: newName }) + } + const info = [ - { name: T.ID, value: ID }, + { name: T.ID, value: ID, dataCy: 'id' }, { name: T.Name, value: NAME, canEdit: actions?.includes?.(CLUSTER_ACTIONS.RENAME), handleEdit: handleRename, + dataCy: 'name', }, ] @@ -41,18 +55,21 @@ const InformationPanel = ({ cluster = {}, handleRename, actions }) => { return ( <> - + ) } -InformationPanel.displayName = 'InformationPanel' - InformationPanel.propTypes = { - actions: PropTypes.arrayOf(PropTypes.string), - handleRename: PropTypes.func, cluster: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), } +InformationPanel.displayName = 'InformationPanel' + export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/Cluster/index.js b/src/fireedge/src/client/components/Tabs/Cluster/index.js index 23c0222f65..0e08ba49eb 100644 --- a/src/fireedge/src/client/components/Tabs/Cluster/index.js +++ b/src/fireedge/src/client/components/Tabs/Cluster/index.js @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useEffect, useState } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { LinearProgress } from '@mui/material' -import { useFetch } from 'client/hooks' import { useAuth } from 'client/features/Auth' -import { useClusterApi } from 'client/features/One' +import { useGetClusterQuery } from 'client/features/OneApi/cluster' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' import Tabs from 'client/components/Tabs' -import { camelCase } from 'client/utils' - -import TabProvider from 'client/components/Tabs/TabProvider' import Info from 'client/components/Tabs/Cluster/Info' const getTabComponent = (tabName) => @@ -34,54 +31,24 @@ const getTabComponent = (tabName) => }[tabName]) const ClusterTabs = memo(({ id }) => { - const { getCluster } = useClusterApi() - const { data, fetchRequest, loading, error } = useFetch(getCluster) - - const handleRefetch = () => fetchRequest(id, { reload: true }) - - const [tabsAvailable, setTabs] = useState(() => []) const { view, getResourceView } = useAuth() + const { isLoading } = useGetClusterQuery({ id }) - useEffect(() => { - fetchRequest(id) - }, [id]) + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.CLUSTER + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} - useEffect(() => { - const infoTabs = getResourceView('CLUSTER')?.['info-tabs'] ?? {} - - setTabs(() => - Object.entries(infoTabs) - ?.filter(([_, { enabled } = {}]) => !!enabled) - ?.map(([tabName, tabProps]) => { - const camelName = camelCase(tabName) - const TabContent = getTabComponent(camelName) - - return ( - TabContent && { - name: camelName, - renderContent: (props) => TabContent({ ...props, tabProps }), - } - ) - }) - ?.filter(Boolean) - ) + return getAvailableInfoTabs(infoTabs, getTabComponent, id) }, [view]) - if ((!data && !error) || loading) { - return - } - - return ( - - - + return isLoading ? ( + + ) : ( + ) }) -ClusterTabs.propTypes = { - id: PropTypes.string.isRequired, -} - +ClusterTabs.propTypes = { id: PropTypes.string.isRequired } ClusterTabs.displayName = 'ClusterTabs' export default ClusterTabs diff --git a/src/fireedge/src/client/components/Tabs/Common/Attribute/Actions.js b/src/fireedge/src/client/components/Tabs/Common/Attribute/Actions.js index a5a7de9bf0..8d1b5b45e2 100644 --- a/src/fireedge/src/client/components/Tabs/Common/Attribute/Actions.js +++ b/src/fireedge/src/client/components/Tabs/Common/Attribute/Actions.js @@ -83,7 +83,7 @@ const Copy = memo( } - tooltipProps={{ open: isCopied }} + tooltipprops={{ open: isCopied }} handleClick={async () => await copy(value)} icon={CopyIcon} {...props} diff --git a/src/fireedge/src/client/components/Tabs/Common/Ownership.js b/src/fireedge/src/client/components/Tabs/Common/Ownership.js index 129afcfd17..3506c01c15 100644 --- a/src/fireedge/src/client/components/Tabs/Common/Ownership.js +++ b/src/fireedge/src/client/components/Tabs/Common/Ownership.js @@ -17,32 +17,27 @@ import { memo } from 'react' import PropTypes from 'prop-types' import { generatePath } from 'react-router-dom' -import { useUserApi, useGroupApi, RESOURCES } from 'client/features/One' +import { useGetUsersQuery } from 'client/features/OneApi/user' +import { useGetGroupsQuery } from 'client/features/OneApi/group' import { List } from 'client/components/Tabs/Common' import { T, SERVERADMIN_ID, ACTIONS } from 'client/constants' import { PATH } from 'client/apps/sunstone/routesOne' const Ownership = memo( ({ actions, groupId, groupName, handleEdit, userId, userName }) => { - const { getUsers } = useUserApi() - const { getGroups } = useGroupApi() + const { data: users = [] } = useGetUsersQuery() + const { data: groups = [] } = useGetGroupsQuery() - const getUserOptions = async () => { - const response = await getUsers() - - return response?.[RESOURCES.user] + const getUserOptions = () => + users ?.filter?.(({ ID } = {}) => ID !== SERVERADMIN_ID) ?.map?.(({ ID, NAME } = {}) => ({ text: NAME, value: ID })) - } - const getGroupOptions = async () => { - const response = await getGroups() - - return response?.[RESOURCES.group]?.map?.(({ ID, NAME } = {}) => ({ + const getGroupOptions = () => + groups?.map?.(({ ID, NAME } = {}) => ({ text: NAME, value: ID, })) - } const ownership = [ { diff --git a/src/fireedge/src/client/components/Tabs/Datastore/Info/index.js b/src/fireedge/src/client/components/Tabs/Datastore/Info/index.js new file mode 100644 index 0000000000..7ac4cfaf2c --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Datastore/Info/index.js @@ -0,0 +1,166 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' +import { Stack } from '@mui/material' + +import { + useGetDatastoreQuery, + useChangeDatastoreOwnershipMutation, + useChangeDatastorePermissionsMutation, + useUpdateDatastoreMutation, +} from 'client/features/OneApi/datastore' +import { + Permissions, + Ownership, + AttributePanel, +} from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/Datastore/Info/information' + +import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' +import { + getActionsAvailable, + filterAttributes, + jsonToXml, +} from 'client/models/Helper' +import { cloneObject, set } from 'client/utils' + +const VCENTER_ATTRIBUTES_REG = + /^VCENTER_(?!(HOST|USER|PASSWORD|DS_IMAGE_DIR|DS_VOLATILE_DIR)$)/ + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Datastore id + * @returns {ReactElement} Information tab + */ +const DatastoreInfoTab = ({ tabProps = {}, id }) => { + const { + information_panel: informationPanel, + permissions_panel: permissionsPanel, + ownership_panel: ownershipPanel, + vcenter_panel: vcenterPanel, + attributes_panel: attributesPanel, + } = tabProps + + const [changeOwnership] = useChangeDatastoreOwnershipMutation() + const [changePermissions] = useChangeDatastorePermissionsMutation() + const [update] = useUpdateDatastoreMutation() + const { data: datastore } = useGetDatastoreQuery({ id }) + + const { UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = datastore + + const handleChangeOwnership = async (newOwnership) => { + await changeOwnership({ id, ...newOwnership }) + } + + const handleChangePermission = async (newPermission) => { + await changePermissions({ id, ...newPermission }) + } + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) + + const { attributes, vcenter: vcenterAttributes } = filterAttributes( + TEMPLATE, + { extra: { vcenter: VCENTER_ATTRIBUTES_REG } } + ) + + const ATTRIBUTE_FUNCTION = { + handleAdd: handleAttributeInXml, + handleEdit: handleAttributeInXml, + handleDelete: handleAttributeInXml, + } + + return ( + + {informationPanel?.enabled && ( + + )} + {permissionsPanel?.enabled && ( + + )} + {ownershipPanel?.enabled && ( + + )} + {attributesPanel?.enabled && ( + + )} + {vcenterPanel?.enabled && vcenterAttributes && ( + + )} + + ) +} + +DatastoreInfoTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + +DatastoreInfoTab.displayName = 'DatastoreInfoTab' + +export default DatastoreInfoTab diff --git a/src/fireedge/src/client/components/Tabs/Datastore/Info/information.js b/src/fireedge/src/client/components/Tabs/Datastore/Info/information.js new file mode 100644 index 0000000000..fae000dbc1 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Datastore/Info/information.js @@ -0,0 +1,97 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement } from 'react' +import PropTypes from 'prop-types' + +import { useRenameDatastoreMutation } from 'client/features/OneApi/datastore' +import { StatusChip, LinearProgressWithLabel } from 'client/components/Status' +import { List } from 'client/components/Tabs/Common' + +import { getState, getType, getCapacityInfo } from 'client/models/Datastore' +import { stringToBoolean } from 'client/models/Helper' +import { prettyBytes } from 'client/utils' +import { T, Datastore, DATASTORE_ACTIONS } from 'client/constants' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {Datastore} props.datastore - datastore resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ datastore = {}, actions }) => { + const [rename] = useRenameDatastoreMutation() + + const { ID, NAME, BASE_PATH, TEMPLATE } = datastore + + const isShared = stringToBoolean(TEMPLATE.SHARED) + const limit = + !isShared && TEMPLATE.LIMIT_MB ? prettyBytes(TEMPLATE.LIMIT_MB, 'MB') : '-' + + const { percentOfUsed, percentLabel } = getCapacityInfo(datastore) + const { color: stateColor, name: stateName } = getState(datastore) + const dsTypeName = getType(datastore) + + const handleRename = async (_, newName) => { + await rename({ id: ID, name: newName }) + } + + const info = [ + { name: T.ID, value: ID, dataCy: 'id' }, + { + name: T.Name, + value: NAME, + dataCy: 'name', + canEdit: actions?.includes?.(DATASTORE_ACTIONS.RENAME), + handleEdit: handleRename, + }, + { + name: T.State, + value: , + dataCy: 'state', + }, + { name: T.Type, value: dsTypeName, dataCy: 'type' }, + { name: T.BasePath, value: BASE_PATH, dataCy: 'base_path' }, + { + name: T.Capacity, + value: ( + + ), + dataCy: 'capacity', + }, + { name: T.Limit, value: limit, dataCy: 'limit' }, + ] + + return ( + <> + + + ) +} + +InformationPanel.propTypes = { + datastore: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), +} + +InformationPanel.displayName = 'InformationPanel' + +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/Datastore/index.js b/src/fireedge/src/client/components/Tabs/Datastore/index.js new file mode 100644 index 0000000000..60a6c21d5f --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Datastore/index.js @@ -0,0 +1,54 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo, useMemo } from 'react' +import PropTypes from 'prop-types' +import { LinearProgress } from '@mui/material' + +import { useAuth } from 'client/features/Auth' +import { useGetDatastoreQuery } from 'client/features/OneApi/datastore' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' + +import Tabs from 'client/components/Tabs' +import Info from 'client/components/Tabs/Datastore/Info' + +const getTabComponent = (tabName) => + ({ + info: Info, + }[tabName]) + +const DatastoreTabs = memo(({ id }) => { + const { view, getResourceView } = useAuth() + const { isLoading } = useGetDatastoreQuery({ id }) + + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.DATASTORE + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} + + return getAvailableInfoTabs(infoTabs, getTabComponent, id) + }, [view]) + + return isLoading ? ( + + ) : ( + + ) +}) + +DatastoreTabs.propTypes = { id: PropTypes.string.isRequired } +DatastoreTabs.displayName = 'DatastoreTabs' + +export default DatastoreTabs diff --git a/src/fireedge/src/client/components/Tabs/Group/Info/index.js b/src/fireedge/src/client/components/Tabs/Group/Info/index.js new file mode 100644 index 0000000000..99ee14cdfb --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Group/Info/index.js @@ -0,0 +1,111 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' +import { Stack } from '@mui/material' + +import { + useGetGroupQuery, + useUpdateGroupMutation, +} from 'client/features/OneApi/group' +import { AttributePanel } from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/Group/Info/information' + +import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' +import { + jsonToXml, + getActionsAvailable, + filterAttributes, +} from 'client/models/Helper' +import { cloneObject, set } from 'client/utils' + +const HIDDEN_ATTRIBUTES_REG = /^(SUNSTONE|OPENNEBULA)$/ + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Group id + * @returns {ReactElement} Information tab + */ +const GroupInfoTab = ({ tabProps = {}, id }) => { + const { + information_panel: informationPanel, + attributes_panel: attributesPanel, + } = tabProps + + const [update] = useUpdateGroupMutation() + const { data: group } = useGetGroupQuery(id) + const { TEMPLATE } = group + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) + + const { attributes } = filterAttributes(TEMPLATE, { + hidden: HIDDEN_ATTRIBUTES_REG, + }) + + const ATTRIBUTE_FUNCTION = { + handleAdd: handleAttributeInXml, + handleEdit: handleAttributeInXml, + handleDelete: handleAttributeInXml, + } + + return ( + + {informationPanel?.enabled && ( + + )} + {attributesPanel?.enabled && ( + + )} + + ) +} + +GroupInfoTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + +GroupInfoTab.displayName = 'GroupInfoTab' + +export default GroupInfoTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/List.js b/src/fireedge/src/client/components/Tabs/Group/Info/information.js similarity index 59% rename from src/fireedge/src/client/components/Tabs/Vm/Network/List.js rename to src/fireedge/src/client/components/Tabs/Group/Info/information.js index 98860b077c..27b80117c0 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Network/List.js +++ b/src/fireedge/src/client/components/Tabs/Group/Info/information.js @@ -13,34 +13,44 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' -import NetworkItem from 'client/components/Tabs/Vm/Network/Item' +import { List } from 'client/components/Tabs/Common' +import { T, Group } from 'client/constants' -const NetworkList = ({ nics, actions }) => ( -
- {nics.map((nic) => { - const { IP, MAC, ADDRESS } = nic - const key = IP ?? MAC ?? ADDRESS // address only exists form PCI nics +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {Group} props.group - Group resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ group = {}, actions: _ }) => { + const { ID, NAME } = group - return - })} -
-) + const info = [ + { name: T.ID, value: ID, dataCy: 'id' }, + { name: T.Name, value: NAME, dataCy: 'name' }, + ] -NetworkList.propTypes = { - actions: PropTypes.arrayOf(PropTypes.string), - nics: PropTypes.array, + return ( + <> + + + ) } -NetworkList.displayName = 'NetworkList' +InformationPanel.propTypes = { + group: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), +} -export default NetworkList +InformationPanel.displayName = 'InformationPanel' + +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/Vm/History/List.js b/src/fireedge/src/client/components/Tabs/Group/index.js similarity index 52% rename from src/fireedge/src/client/components/Tabs/Vm/History/List.js rename to src/fireedge/src/client/components/Tabs/Group/index.js index b300b00f1c..e718c37ea9 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/History/List.js +++ b/src/fireedge/src/client/components/Tabs/Group/index.js @@ -13,24 +13,42 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' +import { LinearProgress } from '@mui/material' -import HistoryItem from 'client/components/Tabs/Vm/History/Item' +import { useAuth } from 'client/features/Auth' +import { useGetGroupQuery } from 'client/features/OneApi/group' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' -const HistoryList = ({ records, actions }) => ( -
- {records.map((history, idx) => ( - - ))} -
-) +import Tabs from 'client/components/Tabs' +import Info from 'client/components/Tabs/Group/Info' -HistoryList.propTypes = { - records: PropTypes.array, - actions: PropTypes.arrayOf(PropTypes.string), -} +const getTabComponent = (tabName) => + ({ + info: Info, + }[tabName]) -HistoryList.displayName = 'HistoryList' +const GroupTabs = memo(({ id }) => { + const { view, getResourceView } = useAuth() + const { isLoading } = useGetGroupQuery(id) -export default HistoryList + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.GROUP + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} + + return getAvailableInfoTabs(infoTabs, getTabComponent, id) + }, [view]) + + return isLoading ? ( + + ) : ( + + ) +}) + +GroupTabs.propTypes = { id: PropTypes.string.isRequired } +GroupTabs.displayName = 'GroupTabs' + +export default GroupTabs diff --git a/src/fireedge/src/client/components/Tabs/Host/Info/index.js b/src/fireedge/src/client/components/Tabs/Host/Info/index.js index 96c56c382d..103afe3710 100644 --- a/src/fireedge/src/client/components/Tabs/Host/Info/index.js +++ b/src/fireedge/src/client/components/Tabs/Host/Info/index.js @@ -13,18 +13,24 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext } from 'react' +import { ReactElement, useCallback } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useHostApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useGetHostQuery, + useUpdateHostMutation, +} from 'client/features/OneApi/host' import { AttributePanel } from 'client/components/Tabs/Common' import Information from 'client/components/Tabs/Host/Info/information' import { Tr } from 'client/components/HOC' import { T } from 'client/constants' -import * as Helper from 'client/models/Helper' +import { + getActionsAvailable, + filterAttributes, + jsonToXml, +} from 'client/models/Helper' import { cloneObject, set } from 'client/utils' const NSX_ATTRIBUTES_REG = /^NSX_/ @@ -32,7 +38,15 @@ const VCENTER_ATTRIBUTES_REG = /^VCENTER_(?!(RESOURCE_POOL)$)/ const HIDDEN_ATTRIBUTES_REG = /^(HOST|VM|WILDS|ZOMBIES|RESERVED_CPU|RESERVED_MEM|EC2_ACCESS|EC2_SECRET|CAPACITY|REGION_NAME)$/ -const HostInfoTab = ({ tabProps = {} }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Host id + * @returns {ReactElement} Information tab + */ +const HostInfoTab = ({ tabProps = {}, id }) => { const { information_panel: informationPanel, vcenter_panel: vcenterPanel, @@ -40,35 +54,28 @@ const HostInfoTab = ({ tabProps = {} }) => { attributes_panel: attributesPanel, } = tabProps - const { rename, updateUserTemplate } = useHostApi() - const { handleRefetch, data: host = {} } = useContext(TabContext) - const { ID, TEMPLATE } = host - - const handleRename = async (newName) => { - const response = await rename(ID, newName) - String(response) === String(ID) && (await handleRefetch?.()) - } + const [updateUserTemplate] = useUpdateHostMutation() + const { data: host = {} } = useGetHostQuery(id) + const { TEMPLATE } = host const handleAttributeInXml = async (path, newValue) => { const newTemplate = cloneObject(TEMPLATE) - set(newTemplate, path, newValue) - const xml = Helper.jsonToXml(newTemplate) - - // 0: Replace the whole template - const response = await updateUserTemplate(ID, xml, 0) - - String(response) === String(ID) && (await handleRefetch?.()) + const xml = jsonToXml(newTemplate) + await updateUserTemplate({ id, template: xml, replace: 0 }) } - const getActions = (actions) => Helper.getActionsAvailable(actions) + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) const { attributes, nsx: nsxAttributes, vcenter: vcenterAttributes, - } = Helper.filterAttributes(TEMPLATE, { + } = filterAttributes(TEMPLATE, { extra: { vcenter: VCENTER_ATTRIBUTES_REG, nsx: NSX_ATTRIBUTES_REG, @@ -83,18 +90,15 @@ const HostInfoTab = ({ tabProps = {} }) => { } return ( -
{informationPanel?.enabled && ( )} @@ -122,12 +126,13 @@ const HostInfoTab = ({ tabProps = {} }) => { title={`NSX ${Tr(T.Information)}`} /> )} -
+ ) } HostInfoTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } HostInfoTab.displayName = 'HostInfoTab' diff --git a/src/fireedge/src/client/components/Tabs/Host/Info/information.js b/src/fireedge/src/client/components/Tabs/Host/Info/information.js index 4b415b0ecd..e0fdfd05bc 100644 --- a/src/fireedge/src/client/components/Tabs/Host/Info/information.js +++ b/src/fireedge/src/client/components/Tabs/Host/Info/information.js @@ -13,36 +13,55 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' import { generatePath } from 'react-router' +import { useRenameHostMutation } from 'client/features/OneApi/host' +import { useGetDatastoresQuery } from 'client/features/OneApi/datastore' import { StatusChip, LinearProgressWithLabel } from 'client/components/Status' import { List } from 'client/components/Tabs/Common' import { getState, getDatastores, getAllocatedInfo } from 'client/models/Host' import { getCapacityInfo } from 'client/models/Datastore' -import { T, VM_ACTIONS } from 'client/constants' +import { T, VM_ACTIONS, Host } from 'client/constants' import { PATH } from 'client/apps/sunstone/routesOne' -const InformationPanel = ({ host = {}, handleRename, actions }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {Host} props.host - Host resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ host = {}, actions }) => { + const [renameHost] = useRenameHostMutation() + const { data: datastores = [] } = useGetDatastoresQuery() + const { ID, NAME, IM_MAD, VM_MAD, CLUSTER_ID, CLUSTER } = host const { name: stateName, color: stateColor } = getState(host) - const datastores = getDatastores(host) const { percentCpuUsed, percentCpuLabel, percentMemUsed, percentMemLabel } = getAllocatedInfo(host) + const handleRename = async (_, newName) => { + await renameHost({ id: ID, name: newName }) + } + const info = [ - { name: T.ID, value: ID }, + { name: T.ID, value: ID, dataCy: 'id' }, { name: T.Name, value: NAME, canEdit: actions?.includes?.(VM_ACTIONS.RENAME), handleEdit: handleRename, + dataCy: 'name', }, { name: T.State, - value: , + value: ( + + ), }, { name: T.Cluster, @@ -50,9 +69,10 @@ const InformationPanel = ({ host = {}, handleRename, actions }) => { link: !Number.isNaN(+CLUSTER_ID) && generatePath(PATH.INFRASTRUCTURE.CLUSTERS.DETAIL, { id: CLUSTER_ID }), + dataCy: 'clusterid', }, - { name: T.IM_MAD, value: IM_MAD }, - { name: T.VM_MAD, value: VM_MAD }, + { name: T.IM_MAD, value: IM_MAD, dataCy: 'immad' }, + { name: T.VM_MAD, value: VM_MAD, dataCy: 'vmmad' }, ] const capacity = [ @@ -76,11 +96,13 @@ const InformationPanel = ({ host = {}, handleRename, actions }) => { }, ] - const datastore = datastores.map((ds) => { - const { percentOfUsed, percentLabel } = getCapacityInfo(ds) + const infoFromDatastores = getDatastores(host).map((dsHost) => { + const { percentOfUsed, percentLabel } = getCapacityInfo(dsHost) + const dsName = datastores.find((ds) => +ds.ID === +dsHost.ID)?.NAME ?? '--' return { - name: `#${ds?.ID}`, // TODO: add datastore name + name: `#${dsHost.ID} ${dsName}`, + dataCy: `ds-id-${dsHost.ID}`, value: ( ), @@ -95,7 +117,7 @@ const InformationPanel = ({ host = {}, handleRename, actions }) => { containerProps={{ style: { gridRow: 'span 2' } }} /> - + ) } diff --git a/src/fireedge/src/client/components/Tabs/Host/index.js b/src/fireedge/src/client/components/Tabs/Host/index.js index c18d39a797..ec4f081682 100644 --- a/src/fireedge/src/client/components/Tabs/Host/index.js +++ b/src/fireedge/src/client/components/Tabs/Host/index.js @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useEffect, useState } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { LinearProgress } from '@mui/material' -import { useFetch, useSocket } from 'client/hooks' import { useAuth } from 'client/features/Auth' -import { useHostApi } from 'client/features/One' +import { useGetHostQuery } from 'client/features/OneApi/host' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' import Tabs from 'client/components/Tabs' -import { camelCase } from 'client/utils' - -import TabProvider from 'client/components/Tabs/TabProvider' import Info from 'client/components/Tabs/Host/Info' const getTabComponent = (tabName) => @@ -34,59 +31,24 @@ const getTabComponent = (tabName) => }[tabName]) const HostTabs = memo(({ id }) => { - const { getHooksSocket } = useSocket() - const { getHost } = useHostApi() - - const { data, fetchRequest, loading, error } = useFetch( - getHost, - getHooksSocket({ resource: 'host', id }) - ) - - const handleRefetch = () => fetchRequest(id, { reload: true }) - - const [tabsAvailable, setTabs] = useState(() => []) const { view, getResourceView } = useAuth() + const { isLoading } = useGetHostQuery(id) - useEffect(() => { - fetchRequest(id) - }, [id]) + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.HOST + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} - useEffect(() => { - const infoTabs = getResourceView('HOST')?.['info-tabs'] ?? {} - - setTabs(() => - Object.entries(infoTabs) - ?.filter(([_, { enabled } = {}]) => !!enabled) - ?.map(([tabName, tabProps]) => { - const camelName = camelCase(tabName) - const TabContent = getTabComponent(camelName) - - return ( - TabContent && { - name: camelName, - renderContent: (props) => TabContent({ ...props, tabProps }), - } - ) - }) - ?.filter(Boolean) - ) + return getAvailableInfoTabs(infoTabs, getTabComponent, id) }, [view]) - if ((!data && !error) || loading) { - return - } - - return ( - - - + return isLoading ? ( + + ) : ( + ) }) -HostTabs.propTypes = { - id: PropTypes.string.isRequired, -} - +HostTabs.propTypes = { id: PropTypes.string.isRequired } HostTabs.displayName = 'HostTabs' export default HostTabs diff --git a/src/fireedge/src/client/components/Tabs/Image/Info/index.js b/src/fireedge/src/client/components/Tabs/Image/Info/index.js new file mode 100644 index 0000000000..9531cdc37c --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Image/Info/index.js @@ -0,0 +1,145 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' +import { Stack } from '@mui/material' + +import { + useGetImageQuery, + useChangeImageOwnershipMutation, + useChangeImagePermissionsMutation, + useUpdateImageMutation, +} from 'client/features/OneApi/image' +import { + Permissions, + Ownership, + AttributePanel, +} from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/Image/Info/information' + +import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' +import { getActionsAvailable, jsonToXml } from 'client/models/Helper' +import { cloneObject, set } from 'client/utils' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Image id + * @returns {ReactElement} Information tab + */ +const ImageInfoTab = ({ tabProps = {}, id }) => { + const { + information_panel: informationPanel, + permissions_panel: permissionsPanel, + ownership_panel: ownershipPanel, + attributes_panel: attributesPanel, + } = tabProps + + const [changeOwnership] = useChangeImageOwnershipMutation() + const [changePermissions] = useChangeImagePermissionsMutation() + const [update] = useUpdateImageMutation() + const { data: image } = useGetImageQuery({ id }) + + const { UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = image + + const handleChangeOwnership = async (newOwnership) => { + await changeOwnership({ id, ...newOwnership }) + } + + const handleChangePermission = async (newPermission) => { + await changePermissions({ id, ...newPermission }) + } + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) + + const ATTRIBUTE_FUNCTION = { + handleAdd: handleAttributeInXml, + handleEdit: handleAttributeInXml, + handleDelete: handleAttributeInXml, + } + + return ( + + {informationPanel?.enabled && ( + + )} + {permissionsPanel?.enabled && ( + + )} + {ownershipPanel?.enabled && ( + + )} + {attributesPanel?.enabled && ( + + )} + + ) +} + +ImageInfoTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + +ImageInfoTab.displayName = 'ImageInfoTab' + +export default ImageInfoTab diff --git a/src/fireedge/src/client/components/Tabs/Image/Info/information.js b/src/fireedge/src/client/components/Tabs/Image/Info/information.js new file mode 100644 index 0000000000..9a3b51f620 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Image/Info/information.js @@ -0,0 +1,155 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement } from 'react' +import PropTypes from 'prop-types' +import { generatePath } from 'react-router-dom' + +import { + useRenameImageMutation, + useChangeImageTypeMutation, + usePersistentImageMutation, +} from 'client/features/OneApi/image' +import { StatusChip } from 'client/components/Status' +import { List } from 'client/components/Tabs/Common' + +import { getType, getState } from 'client/models/Image' +import { timeToString, booleanToString } from 'client/models/Helper' +import { arrayToOptions, prettyBytes } from 'client/utils' +import { T, Image, IMAGE_ACTIONS, IMAGE_TYPES } from 'client/constants' +import { PATH } from 'client/apps/sunstone/routesOne' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {Image} props.image - Image resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ image = {}, actions }) => { + const [rename] = useRenameImageMutation() + const [changeType] = useChangeImageTypeMutation() + const [persistent] = usePersistentImageMutation() + + const { + ID, + NAME, + SIZE, + PERSISTENT, + REGTIME, + DATASTORE_ID, + DATASTORE = '--', + VMS, + } = image + + const { color: stateColor, name: stateName } = getState(image) + const imageTypeName = getType(image) + + const handleRename = async (_, newName) => { + await rename({ id: ID, name: newName }) + } + + const handleChangeType = async (_, newType) => { + await changeType({ id: ID, type: newType }) + } + + const handleChangePersistent = async (_, newPersistent) => { + await persistent({ id: ID, persistent: !!+newPersistent }) + } + + const getTypeOptions = () => arrayToOptions(IMAGE_TYPES, { addEmpty: false }) + + const getPersistentOptions = () => + arrayToOptions([0, 1], { + addEmpty: false, + getText: booleanToString, + getValue: String, + }) + + const info = [ + { name: T.ID, value: ID, dataCy: 'id' }, + { + name: T.Name, + value: NAME, + dataCy: 'name', + canEdit: actions?.includes?.(IMAGE_ACTIONS.RENAME), + handleEdit: handleRename, + }, + DATASTORE_ID && { + name: T.Datastore, + value: `#${DATASTORE_ID} ${DATASTORE}`, + link: + !Number.isNaN(+DATASTORE_ID) && + generatePath(PATH.STORAGE.DATASTORES.DETAIL, { id: DATASTORE_ID }), + dataCy: 'datastoreId', + }, + { + name: T.RegistrationTime, + value: timeToString(REGTIME), + dataCy: 'regtime', + }, + { + name: T.Type, + value: imageTypeName, + valueInOptionList: imageTypeName, + canEdit: actions?.includes?.(IMAGE_ACTIONS.CHANGE_TYPE), + handleGetOptionList: getTypeOptions, + handleEdit: handleChangeType, + dataCy: 'type', + }, + { + name: T.Persistent, + value: booleanToString(+PERSISTENT), + valueInOptionList: PERSISTENT, + canEdit: actions?.includes?.(IMAGE_ACTIONS.CHANGE_PERS), + handleGetOptionList: getPersistentOptions, + handleEdit: handleChangePersistent, + dataCy: 'persistent', + }, + { + name: T.Size, + value: prettyBytes(SIZE, 'MB'), + dataCy: 'size', + }, + { + name: T.State, + value: , + }, + { + name: T.RunningVMs, + value: `${[VMS?.ID ?? []].flat().length || 0}`, + }, + ] + + return ( + <> + + + ) +} + +InformationPanel.propTypes = { + image: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), +} + +InformationPanel.displayName = 'InformationPanel' + +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/Image/index.js b/src/fireedge/src/client/components/Tabs/Image/index.js new file mode 100644 index 0000000000..12e7e22359 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Image/index.js @@ -0,0 +1,54 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo, useMemo } from 'react' +import PropTypes from 'prop-types' +import { LinearProgress } from '@mui/material' + +import { useAuth } from 'client/features/Auth' +import { useGetImageQuery } from 'client/features/OneApi/image' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' + +import Tabs from 'client/components/Tabs' +import Info from 'client/components/Tabs/Image/Info' + +const getTabComponent = (tabName) => + ({ + info: Info, + }[tabName]) + +const ImageTabs = memo(({ id }) => { + const { view, getResourceView } = useAuth() + const { isLoading } = useGetImageQuery({ id }) + + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.IMAGE + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} + + return getAvailableInfoTabs(infoTabs, getTabComponent, id) + }, [view]) + + return isLoading ? ( + + ) : ( + + ) +}) + +ImageTabs.propTypes = { id: PropTypes.string.isRequired } +ImageTabs.displayName = 'ImageTabs' + +export default ImageTabs diff --git a/src/fireedge/src/client/components/Tabs/Marketplace/Info/index.js b/src/fireedge/src/client/components/Tabs/Marketplace/Info/index.js new file mode 100644 index 0000000000..8efc67f9c2 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Marketplace/Info/index.js @@ -0,0 +1,145 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' +import { Stack } from '@mui/material' + +import { + useGetMarketplaceQuery, + useChangeMarketplaceOwnershipMutation, + useChangeMarketplacePermissionsMutation, + useUpdateMarketplaceMutation, +} from 'client/features/OneApi/marketplace' +import { + Permissions, + Ownership, + AttributePanel, +} from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/Marketplace/Info/information' + +import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' +import { getActionsAvailable, jsonToXml } from 'client/models/Helper' +import { cloneObject, set } from 'client/utils' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Marketplace id + * @returns {ReactElement} Information tab + */ +const MarketplaceInfoTab = ({ tabProps = {}, id }) => { + const { + information_panel: informationPanel, + permissions_panel: permissionsPanel, + ownership_panel: ownershipPanel, + attributes_panel: attributesPanel, + } = tabProps + + const [changeOwnership] = useChangeMarketplaceOwnershipMutation() + const [changePermissions] = useChangeMarketplacePermissionsMutation() + const [update] = useUpdateMarketplaceMutation() + const { data: marketplace } = useGetMarketplaceQuery({ id }) + + const { UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = marketplace + + const handleChangeOwnership = async (newOwnership) => { + await changeOwnership({ id, ...newOwnership }) + } + + const handleChangePermission = async (newPermission) => { + await changePermissions({ id, ...newPermission }) + } + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) + + const ATTRIBUTE_FUNCTION = { + handleAdd: handleAttributeInXml, + handleEdit: handleAttributeInXml, + handleDelete: handleAttributeInXml, + } + + return ( + + {informationPanel?.enabled && ( + + )} + {permissionsPanel?.enabled && ( + + )} + {ownershipPanel?.enabled && ( + + )} + {attributesPanel?.enabled && ( + + )} + + ) +} + +MarketplaceInfoTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + +MarketplaceInfoTab.displayName = 'MarketplaceInfoTab' + +export default MarketplaceInfoTab diff --git a/src/fireedge/src/client/components/Tabs/Marketplace/Info/information.js b/src/fireedge/src/client/components/Tabs/Marketplace/Info/information.js new file mode 100644 index 0000000000..ea7d9266a5 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Marketplace/Info/information.js @@ -0,0 +1,92 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement } from 'react' +import PropTypes from 'prop-types' + +import { useRenameMarketplaceMutation } from 'client/features/OneApi/marketplace' +import { StatusChip, LinearProgressWithLabel } from 'client/components/Status' +import { List } from 'client/components/Tabs/Common' + +import { getState, getCapacityInfo } from 'client/models/Marketplace' +import { T, Marketplace, MARKETPLACE_ACTIONS } from 'client/constants' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {Marketplace} props.marketplace - Marketplace resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ marketplace = {}, actions }) => { + const [rename] = useRenameMarketplaceMutation() + + const { ID, NAME, MARKET_MAD } = marketplace + + const { color: stateColor, name: stateName } = getState(marketplace) + const { percentOfUsed, percentLabel } = getCapacityInfo(marketplace) + + const handleRename = async (_, newName) => { + await rename({ id: ID, name: newName }) + } + + const info = [ + { name: T.ID, value: ID, dataCy: 'id' }, + { + name: T.Name, + value: NAME, + dataCy: 'name', + canEdit: actions?.includes?.(MARKETPLACE_ACTIONS.RENAME), + handleEdit: handleRename, + }, + { + name: T.Driver, + value: MARKET_MAD, + dataCy: 'market_mad', + }, + { + name: T.State, + value: , + dataCy: 'state', + }, + { + name: T.Capacity, + value: ( + + ), + dataCy: 'capacity', + }, + ] + + return ( + <> + + + ) +} + +InformationPanel.propTypes = { + marketplace: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), +} + +InformationPanel.displayName = 'InformationPanel' + +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/Marketplace/index.js b/src/fireedge/src/client/components/Tabs/Marketplace/index.js new file mode 100644 index 0000000000..9e17719f1c --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Marketplace/index.js @@ -0,0 +1,54 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo, useMemo } from 'react' +import PropTypes from 'prop-types' +import { LinearProgress } from '@mui/material' + +import { useAuth } from 'client/features/Auth' +import { useGetMarketplaceQuery } from 'client/features/OneApi/marketplace' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' + +import Tabs from 'client/components/Tabs' +import Info from 'client/components/Tabs/Marketplace/Info' + +const getTabComponent = (tabName) => + ({ + info: Info, + }[tabName]) + +const MarketplaceTabs = memo(({ id }) => { + const { view, getResourceView } = useAuth() + const { isLoading } = useGetMarketplaceQuery({ id }) + + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.MARKETPLACE + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} + + return getAvailableInfoTabs(infoTabs, getTabComponent, id) + }, [view]) + + return isLoading ? ( + + ) : ( + + ) +}) + +MarketplaceTabs.propTypes = { id: PropTypes.string.isRequired } +MarketplaceTabs.displayName = 'MarketplaceTabs' + +export default MarketplaceTabs diff --git a/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/index.js b/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/index.js index fe59ab25b7..d40d3438d8 100644 --- a/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/index.js +++ b/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/index.js @@ -13,12 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext } from 'react' +import { ReactElement, useCallback } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useMarketplaceAppApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useGetMarketplaceAppQuery, + useChangeAppOwnershipMutation, + useChangeAppPermissionsMutation, + useUpdateAppMutation, +} from 'client/features/OneApi/marketplaceApp' import { Permissions, Ownership, @@ -27,17 +31,25 @@ import { import Information from 'client/components/Tabs/MarketplaceApp/Info/information' import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' import { getActionsAvailable, filterAttributes, jsonToXml, } from 'client/models/Helper' import { cloneObject, set } from 'client/utils' -import { T } from 'client/constants' const HIDDEN_ATTRIBUTES_REG = /^(VMTEMPLATE64|APPTEMPLATE64)$/ -const MarketplaceAppInfoTab = ({ tabProps = {} }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Marketplace App id + * @returns {ReactElement} Information tab + */ +const MarketplaceAppInfoTab = ({ tabProps = {}, id }) => { const { information_panel: informationPanel, permissions_panel: permissionsPanel, @@ -45,58 +57,48 @@ const MarketplaceAppInfoTab = ({ tabProps = {} }) => { attributes_panel: attributesPanel, } = tabProps - const { rename, changeOwnership, changePermissions, updateTemplate } = - useMarketplaceAppApi() - const { handleRefetch, data: marketplaceApp = {} } = useContext(TabContext) - const { ID, UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = marketplaceApp + const [changeOwnership] = useChangeAppOwnershipMutation() + const [changePermissions] = useChangeAppPermissionsMutation() + const [updateTemplate] = useUpdateAppMutation() + const { data: app = {} } = useGetMarketplaceAppQuery(id) + const { UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = app const handleChangeOwnership = async (newOwnership) => { - const response = await changeOwnership(ID, newOwnership) - String(response) === String(ID) && (await handleRefetch?.()) + await changeOwnership({ id, ...newOwnership }) } const handleChangePermission = async (newPermission) => { - const response = await changePermissions(ID, newPermission) - String(response) === String(ID) && (await handleRefetch?.()) - } - - const handleRename = async (_, newName) => { - const response = await rename(ID, newName) - String(response) === String(ID) && (await handleRefetch?.()) + await changePermissions({ id, ...newPermission }) } const handleAttributeInXml = async (path, newValue) => { const newTemplate = cloneObject(TEMPLATE) - set(newTemplate, path, newValue) const xml = jsonToXml(newTemplate) - - // 0: Replace the whole template - const response = await updateTemplate(ID, xml, 0) - String(response) === String(ID) && (await handleRefetch?.()) + await updateTemplate({ id, template: xml, replace: 0 }) } - const getActions = (actions) => getActionsAvailable(actions) + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) const { attributes } = filterAttributes(TEMPLATE, { hidden: HIDDEN_ATTRIBUTES_REG, }) return ( -
{informationPanel?.enabled && ( )} {permissionsPanel?.enabled && ( @@ -134,12 +136,13 @@ const MarketplaceAppInfoTab = ({ tabProps = {} }) => { handleDelete={handleAttributeInXml} /> )} -
+ ) } MarketplaceAppInfoTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } MarketplaceAppInfoTab.displayName = 'MarketplaceAppInfoTab' diff --git a/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/information.js b/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/information.js index 35b96ee4a7..869c76cd13 100644 --- a/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/information.js +++ b/src/fireedge/src/client/components/Tabs/MarketplaceApp/Info/information.js @@ -13,20 +13,31 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' import { generatePath } from 'react-router' +import { useRenameAppMutation } from 'client/features/OneApi/marketplaceApp' import { StatusChip } from 'client/components/Status' import { List } from 'client/components/Tabs/Common' import { getType, getState } from 'client/models/MarketplaceApp' import { timeToString, levelLockToString } from 'client/models/Helper' import { prettyBytes } from 'client/utils' -import { T, MARKETPLACE_APP_ACTIONS } from 'client/constants' +import { T, MARKETPLACE_APP_ACTIONS, MarketplaceApp } from 'client/constants' import { PATH } from 'client/apps/sunstone/routesOne' -const InformationPanel = ({ marketplaceApp = {}, handleRename, actions }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {MarketplaceApp} props.app - Marketplace App resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ app = {}, actions }) => { + const [rename] = useRenameAppMutation() + const { ID, NAME, @@ -37,17 +48,23 @@ const InformationPanel = ({ marketplaceApp = {}, handleRename, actions }) => { SIZE, FORMAT, VERSION, - } = marketplaceApp - const typeName = getType(marketplaceApp) - const { name: stateName, color: stateColor } = getState(marketplaceApp) + } = app + + const typeName = getType(app) + const { name: stateName, color: stateColor } = getState(app) + + const handleRename = async (_, newName) => { + await rename({ id: ID, name: newName }) + } const info = [ - { name: T.ID, value: ID }, + { name: T.ID, value: ID, dataCy: 'id' }, { name: T.Name, value: NAME, canEdit: actions?.includes?.(MARKETPLACE_APP_ACTIONS.RENAME), handleEdit: handleRename, + dataCy: 'name', }, { name: T.Marketplace, @@ -80,12 +97,11 @@ const InformationPanel = ({ marketplaceApp = {}, handleRename, actions }) => { ) } -InformationPanel.displayName = 'InformationPanel' - InformationPanel.propTypes = { actions: PropTypes.arrayOf(PropTypes.string), - handleRename: PropTypes.func, - marketplaceApp: PropTypes.object, + app: PropTypes.object, } +InformationPanel.displayName = 'InformationPanel' + export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/MarketplaceApp/Template.js b/src/fireedge/src/client/components/Tabs/MarketplaceApp/Template.js index c856620039..35e2911ddd 100644 --- a/src/fireedge/src/client/components/Tabs/MarketplaceApp/Template.js +++ b/src/fireedge/src/client/components/Tabs/MarketplaceApp/Template.js @@ -13,26 +13,32 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext, useMemo } from 'react' +import { useMemo, ReactElement } from 'react' +import PropTypes from 'prop-types' import { Accordion, AccordionDetails, AccordionSummary } from '@mui/material' import { NavArrowDown as ExpandMoreIcon } from 'iconoir-react' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { useGetMarketplaceAppQuery } from 'client/features/OneApi/marketplaceApp' import { decodeBase64 } from 'client/utils' import { Translate } from 'client/components/HOC' import { T } from 'client/constants' -const AppTemplateTab = () => { - const { data: marketplaceApp = {} } = useContext(TabContext) - const { - TEMPLATE: { APPTEMPLATE64, VMTEMPLATE64 }, - } = marketplaceApp +/** + * Renders App template tab. + * + * @param {object} props - Props + * @param {string} props.id - Marketplace App id + * @returns {ReactElement} App Template tab + */ +const AppTemplateTab = ({ id }) => { + const { data: marketplaceApp = {} } = useGetMarketplaceAppQuery(id) + const { APPTEMPLATE64, VMTEMPLATE64 } = marketplaceApp?.TEMPLATE const appTemplate = useMemo( () => decodeBase64(APPTEMPLATE64), [APPTEMPLATE64] ) + const vmTemplate = useMemo(() => decodeBase64(VMTEMPLATE64), [VMTEMPLATE64]) return ( @@ -69,6 +75,11 @@ const AppTemplateTab = () => { ) } +AppTemplateTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + AppTemplateTab.displayName = 'AppTemplateTab' export default AppTemplateTab diff --git a/src/fireedge/src/client/components/Tabs/MarketplaceApp/index.js b/src/fireedge/src/client/components/Tabs/MarketplaceApp/index.js index 0c05341c0a..bb0900ce7d 100644 --- a/src/fireedge/src/client/components/Tabs/MarketplaceApp/index.js +++ b/src/fireedge/src/client/components/Tabs/MarketplaceApp/index.js @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useEffect, useState } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { LinearProgress } from '@mui/material' -import { useFetch } from 'client/hooks' import { useAuth } from 'client/features/Auth' -import { useMarketplaceAppApi } from 'client/features/One' +import { useGetMarketplaceAppQuery } from 'client/features/OneApi/marketplaceApp' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' import Tabs from 'client/components/Tabs' -import { camelCase } from 'client/utils' - -import TabProvider from 'client/components/Tabs/TabProvider' import Info from 'client/components/Tabs/MarketplaceApp/Info' import Template from 'client/components/Tabs/MarketplaceApp/Template' @@ -36,54 +33,24 @@ const getTabComponent = (tabName) => }[tabName]) const MarketplaceAppTabs = memo(({ id }) => { - const { getMarketplaceApp } = useMarketplaceAppApi() - const { data, fetchRequest, loading, error } = useFetch(getMarketplaceApp) - - const handleRefetch = () => fetchRequest(id, { reload: true }) - - const [tabsAvailable, setTabs] = useState(() => []) const { view, getResourceView } = useAuth() + const { isLoading } = useGetMarketplaceAppQuery(id) - useEffect(() => { - fetchRequest(id) - }, [id]) + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.APP + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} - useEffect(() => { - const infoTabs = getResourceView('MARKETPLACE-APP')?.['info-tabs'] ?? {} - - setTabs(() => - Object.entries(infoTabs) - ?.filter(([_, { enabled } = {}]) => !!enabled) - ?.map(([tabName, tabProps]) => { - const camelName = camelCase(tabName) - const TabContent = getTabComponent(camelName) - - return ( - TabContent && { - name: camelName, - renderContent: (props) => TabContent({ ...props, tabProps }), - } - ) - }) - ?.filter(Boolean) - ) + return getAvailableInfoTabs(infoTabs, getTabComponent, id) }, [view]) - if ((!data && !error) || loading) { - return - } - - return ( - - - + return isLoading ? ( + + ) : ( + ) }) -MarketplaceAppTabs.propTypes = { - id: PropTypes.string.isRequired, -} - +MarketplaceAppTabs.propTypes = { id: PropTypes.string.isRequired } MarketplaceAppTabs.displayName = 'MarketplaceAppTabs' export default MarketplaceAppTabs diff --git a/src/fireedge/src/client/components/Tabs/User/Info/index.js b/src/fireedge/src/client/components/Tabs/User/Info/index.js index 52d412f153..df781a77db 100644 --- a/src/fireedge/src/client/components/Tabs/User/Info/index.js +++ b/src/fireedge/src/client/components/Tabs/User/Info/index.js @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext } from 'react' +import { ReactElement } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useUserApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useGetUserQuery, + useUpdateUserMutation, +} from 'client/features/OneApi/user' import { AttributePanel } from 'client/components/Tabs/Common' import Information from 'client/components/Tabs/User/Info/information' @@ -30,27 +32,30 @@ import { cloneObject, set } from 'client/utils' const HIDDEN_ATTRIBUTES_REG = /^(SSH_PUBLIC_KEY|SSH_PRIVATE_KEY|SSH_PASSPHRASE|SUNSTONE|FIREEDGE)$/ -const UserInfoTab = ({ tabProps = {} }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - User id + * @returns {ReactElement} Information tab + */ +const UserInfoTab = ({ tabProps = {}, id }) => { const { information_panel: informationPanel, attributes_panel: attributesPanel, } = tabProps - const { updateUser } = useUserApi() - const { handleRefetch, data: user = {} } = useContext(TabContext) - const { ID, TEMPLATE } = user + const [updateUser] = useUpdateUserMutation() + const { data: user = {} } = useGetUserQuery(id) + const { TEMPLATE } = user const handleAttributeInXml = async (path, newValue) => { const newTemplate = cloneObject(TEMPLATE) - set(newTemplate, path, newValue) const xml = Helper.jsonToXml(newTemplate) - - // 0: Replace the whole template - const response = await updateUser(ID, xml, 0) - - String(response) === String(ID) && (await handleRefetch?.()) + await updateUser({ id, template: xml, replace: 0 }) } const getActions = (actions) => Helper.getActionsAvailable(actions) @@ -66,18 +71,16 @@ const UserInfoTab = ({ tabProps = {} }) => { } return ( -
{informationPanel?.enabled && ( )} {attributesPanel?.enabled && attributes && ( @@ -88,12 +91,13 @@ const UserInfoTab = ({ tabProps = {} }) => { title={Tr(T.Attributes)} /> )} -
+ ) } UserInfoTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } UserInfoTab.displayName = 'UserInfoTab' diff --git a/src/fireedge/src/client/components/Tabs/User/Info/information.js b/src/fireedge/src/client/components/Tabs/User/Info/information.js index 7b005b07ba..536ed461b7 100644 --- a/src/fireedge/src/client/components/Tabs/User/Info/information.js +++ b/src/fireedge/src/client/components/Tabs/User/Info/information.js @@ -13,25 +13,29 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' import { List } from 'client/components/Tabs/Common' -import * as Helper from 'client/models/Helper' -import { T } from 'client/constants' +import { stringToBoolean, booleanToString } from 'client/models/Helper' +import { T, User } from 'client/constants' +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {User} props.user - User + * @returns {ReactElement} Information tab + */ const InformationPanel = ({ user = {} }) => { const { ID, NAME, ENABLED } = user - const isEnabled = Helper.stringToBoolean(ENABLED) + const isEnabled = stringToBoolean(ENABLED) const info = [ { name: T.ID, value: ID }, { name: T.Name, value: NAME }, - { - name: T.State, - value: Helper.booleanToString(isEnabled), - }, + { name: T.State, value: booleanToString(isEnabled) }, ] return @@ -40,6 +44,7 @@ const InformationPanel = ({ user = {} }) => { InformationPanel.displayName = 'InformationPanel' InformationPanel.propTypes = { + actions: PropTypes.arrayOf(PropTypes.string), user: PropTypes.object, } diff --git a/src/fireedge/src/client/components/Tabs/User/index.js b/src/fireedge/src/client/components/Tabs/User/index.js index edf0e21b86..c1baaa0d5b 100644 --- a/src/fireedge/src/client/components/Tabs/User/index.js +++ b/src/fireedge/src/client/components/Tabs/User/index.js @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useEffect, useState } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { LinearProgress } from '@mui/material' -import { useFetch } from 'client/hooks' import { useAuth } from 'client/features/Auth' -import { useUserApi } from 'client/features/One' +import { useGetUserQuery } from 'client/features/OneApi/user' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' import Tabs from 'client/components/Tabs' -import { camelCase } from 'client/utils' - -import TabProvider from 'client/components/Tabs/TabProvider' import Info from 'client/components/Tabs/User/Info' const getTabComponent = (tabName) => @@ -34,54 +31,24 @@ const getTabComponent = (tabName) => }[tabName]) const UserTabs = memo(({ id }) => { - const { getUser } = useUserApi() - const { data, fetchRequest, loading, error } = useFetch(getUser) - - const handleRefetch = () => fetchRequest(id, { reload: true }) - - const [tabsAvailable, setTabs] = useState(() => []) const { view, getResourceView } = useAuth() + const { isLoading } = useGetUserQuery(id) - useEffect(() => { - fetchRequest(id) - }, [id]) + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.USER + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} - useEffect(() => { - const infoTabs = getResourceView('USER')?.['info-tabs'] ?? {} - - setTabs(() => - Object.entries(infoTabs) - ?.filter(([_, { enabled } = {}]) => !!enabled) - ?.map(([tabName, tabProps]) => { - const camelName = camelCase(tabName) - const TabContent = getTabComponent(camelName) - - return ( - TabContent && { - name: camelName, - renderContent: (props) => TabContent({ ...props, tabProps }), - } - ) - }) - ?.filter(Boolean) - ) + return getAvailableInfoTabs(infoTabs, getTabComponent, id) }, [view]) - if ((!data && !error) || loading) { - return - } - - return ( - - - + return isLoading ? ( + + ) : ( + ) }) -UserTabs.propTypes = { - id: PropTypes.string.isRequired, -} - +UserTabs.propTypes = { id: PropTypes.string.isRequired } UserTabs.displayName = 'UserTabs' export default UserTabs diff --git a/src/fireedge/src/client/components/Tabs/VNetwork/Info/index.js b/src/fireedge/src/client/components/Tabs/VNetwork/Info/index.js new file mode 100644 index 0000000000..e49713d10e --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/VNetwork/Info/index.js @@ -0,0 +1,184 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' +import { Stack } from '@mui/material' + +import { + useGetVNetworkQuery, + useChangeVNetOwnershipMutation, + useChangeVNetPermissionsMutation, + useUpdateVNetMutation, +} from 'client/features/OneApi/network' +import { + Permissions, + Ownership, + AttributePanel, +} from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/VNetworkTemplate/Info/information' + +import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' +import { + getActionsAvailable, + filterAttributes, + jsonToXml, +} from 'client/models/Helper' +import { cloneObject, set } from 'client/utils' + +const LXC_ATTRIBUTES_REG = /^LXC_/ +const VCENTER_ATTRIBUTES_REG = /^VCENTER_/ +const HIDDEN_ATTRIBUTES_REG = + /^(SECURITY_GROUPS|INBOUND_AVG_BW|INBOUND_PEAK_BW|INBOUND_PEAK_KB|OUTBOUND_AVG_BW|OUTBOUND_PEAK_BW|OUTBOUND_PEAK_KB)$/ + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Virtual network id + * @returns {ReactElement} Information tab + */ +const VNetworkInfoTab = ({ tabProps = {}, id }) => { + const { + information_panel: informationPanel, + permissions_panel: permissionsPanel, + ownership_panel: ownershipPanel, + attributes_panel: attributesPanel, + vcenter_panel: vcenterPanel, + lxc_panel: lxcPanel, + } = tabProps + + const [changeOwnership] = useChangeVNetOwnershipMutation() + const [changePermissions] = useChangeVNetPermissionsMutation() + const [update] = useUpdateVNetMutation() + const { data: vnet } = useGetVNetworkQuery({ id }) + + const { UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = vnet + + const { + attributes, + lxc: lxcAttributes, + vcenter: vcenterAttributes, + } = filterAttributes(TEMPLATE, { + extra: { + vcenter: VCENTER_ATTRIBUTES_REG, + lxc: LXC_ATTRIBUTES_REG, + }, + hidden: HIDDEN_ATTRIBUTES_REG, + }) + + const handleChangeOwnership = async (newOwnership) => { + await changeOwnership({ id, ...newOwnership }) + } + + const handleChangePermission = async (newPermission) => { + await changePermissions({ id, ...newPermission }) + } + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) + + const ATTRIBUTE_FUNCTION = { + handleAdd: handleAttributeInXml, + handleEdit: handleAttributeInXml, + handleDelete: handleAttributeInXml, + } + + return ( + + {informationPanel?.enabled && ( + + )} + {permissionsPanel?.enabled && ( + + )} + {ownershipPanel?.enabled && ( + + )} + {attributesPanel?.enabled && attributes && ( + + )} + {vcenterPanel?.enabled && vcenterAttributes && ( + + )} + {lxcPanel?.enabled && lxcAttributes && ( + + )} + + ) +} + +VNetworkInfoTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + +VNetworkInfoTab.displayName = 'VNetworkInfoTab' + +export default VNetworkInfoTab diff --git a/src/fireedge/src/client/components/Tabs/VNetwork/Info/information.js b/src/fireedge/src/client/components/Tabs/VNetwork/Info/information.js new file mode 100644 index 0000000000..3333ec545b --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/VNetwork/Info/information.js @@ -0,0 +1,68 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement } from 'react' +import PropTypes from 'prop-types' + +import { useRenameVNTemplateMutation } from 'client/features/OneApi/networkTemplate' +import { List } from 'client/components/Tabs/Common' +import { T, VNetwork, VNET_ACTIONS } from 'client/constants' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {VNetwork} props.vnet - Virtual Network resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ vnet = {}, actions }) => { + const [rename] = useRenameVNTemplateMutation() + const { ID, NAME } = vnet + + const handleRename = async (_, newName) => { + await rename({ id: ID, name: newName }) + } + + const info = [ + { name: T.ID, value: ID, dataCy: 'id' }, + { + name: T.Name, + value: NAME, + dataCy: 'name', + canEdit: actions?.includes?.(VNET_ACTIONS.RENAME), + handleEdit: handleRename, + }, + ] + + return ( + <> + + + ) +} + +InformationPanel.propTypes = { + vnet: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), +} + +InformationPanel.displayName = 'InformationPanel' + +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/VNetwork/index.js b/src/fireedge/src/client/components/Tabs/VNetwork/index.js new file mode 100644 index 0000000000..98e84067fd --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/VNetwork/index.js @@ -0,0 +1,54 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo, useMemo } from 'react' +import PropTypes from 'prop-types' +import { LinearProgress } from '@mui/material' + +import { useAuth } from 'client/features/Auth' +import { useGetVNetworkQuery } from 'client/features/OneApi/network' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' + +import Tabs from 'client/components/Tabs' +import Info from 'client/components/Tabs/VNetwork/Info' + +const getTabComponent = (tabName) => + ({ + info: Info, + }[tabName]) + +const VNetworkTabs = memo(({ id }) => { + const { view, getResourceView } = useAuth() + const { isLoading } = useGetVNetworkQuery({ id }) + + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.VNET + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} + + return getAvailableInfoTabs(infoTabs, getTabComponent, id) + }, [view]) + + return isLoading ? ( + + ) : ( + + ) +}) + +VNetworkTabs.propTypes = { id: PropTypes.string.isRequired } +VNetworkTabs.displayName = 'VNetworkTabs' + +export default VNetworkTabs diff --git a/src/fireedge/src/client/components/Tabs/VNetworkTemplate/Info/index.js b/src/fireedge/src/client/components/Tabs/VNetworkTemplate/Info/index.js new file mode 100644 index 0000000000..8d38b79f5f --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/VNetworkTemplate/Info/index.js @@ -0,0 +1,184 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' +import { Stack } from '@mui/material' + +import { + useGetVNTemplateQuery, + useChangeVNTemplateOwnershipMutation, + useChangeVNTemplatePermissionsMutation, + useUpdateVNTemplateMutation, +} from 'client/features/OneApi/networkTemplate' +import { + Permissions, + Ownership, + AttributePanel, +} from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/VNetworkTemplate/Info/information' + +import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' +import { + getActionsAvailable, + filterAttributes, + jsonToXml, +} from 'client/models/Helper' +import { cloneObject, set } from 'client/utils' + +const LXC_ATTRIBUTES_REG = /^LXC_/ +const VCENTER_ATTRIBUTES_REG = /^VCENTER_/ +const HIDDEN_ATTRIBUTES_REG = + /^(AR|CLUSTERS|SECURITY_GROUPS|INBOUND_AVG_BW|INBOUND_PEAK_BW|INBOUND_PEAK_KB|OUTBOUND_AVG_BW|OUTBOUND_PEAK_BW|OUTBOUND_PEAK_KB)$/ + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Virtual network template id + * @returns {ReactElement} Information tab + */ +const VNetTemplateInfoTab = ({ tabProps = {}, id }) => { + const { + information_panel: informationPanel, + permissions_panel: permissionsPanel, + ownership_panel: ownershipPanel, + attributes_panel: attributesPanel, + vcenter_panel: vcenterPanel, + lxc_panel: lxcPanel, + } = tabProps + + const [changeOwnership] = useChangeVNTemplateOwnershipMutation() + const [changePermissions] = useChangeVNTemplatePermissionsMutation() + const [update] = useUpdateVNTemplateMutation() + const { data: vnetTemplate } = useGetVNTemplateQuery({ id }) + + const { UNAME, UID, GNAME, GID, PERMISSIONS, TEMPLATE } = vnetTemplate + + const { + attributes, + lxc: lxcAttributes, + vcenter: vcenterAttributes, + } = filterAttributes(TEMPLATE, { + extra: { + vcenter: VCENTER_ATTRIBUTES_REG, + lxc: LXC_ATTRIBUTES_REG, + }, + hidden: HIDDEN_ATTRIBUTES_REG, + }) + + const handleChangeOwnership = async (newOwnership) => { + await changeOwnership({ id, ...newOwnership }) + } + + const handleChangePermission = async (newPermission) => { + await changePermissions({ id, ...newPermission }) + } + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) + + const ATTRIBUTE_FUNCTION = { + handleAdd: handleAttributeInXml, + handleEdit: handleAttributeInXml, + handleDelete: handleAttributeInXml, + } + + return ( + + {informationPanel?.enabled && ( + + )} + {permissionsPanel?.enabled && ( + + )} + {ownershipPanel?.enabled && ( + + )} + {attributesPanel?.enabled && attributes && ( + + )} + {vcenterPanel?.enabled && vcenterAttributes && ( + + )} + {lxcPanel?.enabled && lxcAttributes && ( + + )} + + ) +} + +VNetTemplateInfoTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + +VNetTemplateInfoTab.displayName = 'VNetTemplateInfoTab' + +export default VNetTemplateInfoTab diff --git a/src/fireedge/src/client/components/Tabs/VNetworkTemplate/Info/information.js b/src/fireedge/src/client/components/Tabs/VNetworkTemplate/Info/information.js new file mode 100644 index 0000000000..3137d7c118 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/VNetworkTemplate/Info/information.js @@ -0,0 +1,68 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement } from 'react' +import PropTypes from 'prop-types' + +import { useRenameVNTemplateMutation } from 'client/features/OneApi/networkTemplate' +import { List } from 'client/components/Tabs/Common' +import { T, VNetworkTemplate, VN_TEMPLATE_ACTIONS } from 'client/constants' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {VNetworkTemplate} props.vnetTemplate - Virtual network template resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ vnetTemplate = {}, actions }) => { + const [rename] = useRenameVNTemplateMutation() + const { ID, NAME } = vnetTemplate + + const handleRename = async (_, newName) => { + await rename({ id: ID, name: newName }) + } + + const info = [ + { name: T.ID, value: ID, dataCy: 'id' }, + { + name: T.Name, + value: NAME, + dataCy: 'name', + canEdit: actions?.includes?.(VN_TEMPLATE_ACTIONS.RENAME), + handleEdit: handleRename, + }, + ] + + return ( + <> + + + ) +} + +InformationPanel.propTypes = { + vnetTemplate: PropTypes.object, + actions: PropTypes.arrayOf(PropTypes.string), +} + +InformationPanel.displayName = 'InformationPanel' + +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/VNetworkTemplate/index.js b/src/fireedge/src/client/components/Tabs/VNetworkTemplate/index.js new file mode 100644 index 0000000000..9b4185751c --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/VNetworkTemplate/index.js @@ -0,0 +1,54 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo, useMemo } from 'react' +import PropTypes from 'prop-types' +import { LinearProgress } from '@mui/material' + +import { useAuth } from 'client/features/Auth' +import { useGetVNTemplateQuery } from 'client/features/OneApi/networkTemplate' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' + +import Tabs from 'client/components/Tabs' +import Info from 'client/components/Tabs/VNetworkTemplate/Info' + +const getTabComponent = (tabName) => + ({ + info: Info, + }[tabName]) + +const VNetTemplateTabs = memo(({ id }) => { + const { view, getResourceView } = useAuth() + const { isLoading } = useGetVNTemplateQuery({ id }) + + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.VN_TEMPLATE + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} + + return getAvailableInfoTabs(infoTabs, getTabComponent, id) + }, [view]) + + return isLoading ? ( + + ) : ( + + ) +}) + +VNetTemplateTabs.propTypes = { id: PropTypes.string.isRequired } +VNetTemplateTabs.displayName = 'VNetTemplateTabs' + +export default VNetTemplateTabs diff --git a/src/fireedge/src/client/components/Tabs/Vm/Capacity/index.js b/src/fireedge/src/client/components/Tabs/Vm/Capacity/index.js index 9f1c50b145..c98725a463 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Capacity/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Capacity/index.js @@ -13,22 +13,27 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext, useMemo } from 'react' +import { ReactElement, useMemo } from 'react' import PropTypes from 'prop-types' -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { useGetVmQuery, useResizeMutation } from 'client/features/OneApi/vm' import InformationPanel from 'client/components/Tabs/Vm/Capacity/information' import { getHypervisor, isAvailableAction } from 'client/models/VirtualMachine' import { getActionsAvailable, jsonToXml } from 'client/models/Helper' -const VmCapacityTab = ({ tabProps: { actions } = {} }) => { - const { resize } = useVmApi() - - const { handleRefetch, data: vm = {} } = useContext(TabContext) - const { ID } = vm +/** + * Renders capacity tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string[]} props.tabProps.actions - Actions tab + * @param {string} props.id - Virtual Machine id + * @returns {ReactElement} Capacity tab + */ +const VmCapacityTab = ({ tabProps: { actions } = {}, id }) => { + const [resizeCapacity] = useResizeMutation() + const { data: vm = {} } = useGetVmQuery(id) const actionsAvailable = useMemo(() => { const hypervisor = getHypervisor(vm) @@ -44,8 +49,7 @@ const VmCapacityTab = ({ tabProps: { actions } = {} }) => { const { enforce, ...restOfData } = formData const template = jsonToXml(restOfData) - const response = await resize(ID, { enforce, template }) - String(response) === String(ID) && (await handleRefetch?.()) + await resizeCapacity({ id: vm.ID, enforce, template }) } return ( @@ -59,6 +63,7 @@ const VmCapacityTab = ({ tabProps: { actions } = {} }) => { VmCapacityTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } VmCapacityTab.displayName = 'VmCapacityTab' diff --git a/src/fireedge/src/client/components/Tabs/Vm/Configuration.js b/src/fireedge/src/client/components/Tabs/Vm/Configuration.js index 2f5b363644..e39d5000c3 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Configuration.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Configuration.js @@ -13,17 +13,24 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext } from 'react' +import { ReactElement } from 'react' +import PropTypes from 'prop-types' import { Accordion, AccordionSummary, AccordionDetails } from '@mui/material' import { NavArrowDown as ExpandMoreIcon } from 'iconoir-react' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { useGetVmQuery } from 'client/features/OneApi/vm' import { Translate } from 'client/components/HOC' import { T } from 'client/constants' -const VmConfigurationTab = () => { - const { data: vm = {} } = useContext(TabContext) +/** + * Renders configuration tab. + * + * @param {object} props - Props + * @param {string} props.id - Virtual machine id + * @returns {ReactElement} Configuration tab + */ +const VmConfigurationTab = ({ id }) => { + const { data: vm = {} } = useGetVmQuery(id) const { TEMPLATE, USER_TEMPLATE } = vm return ( @@ -56,6 +63,11 @@ const VmConfigurationTab = () => { ) } +VmConfigurationTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + VmConfigurationTab.displayName = 'VmConfigurationTab' export default VmConfigurationTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/History/Item.js b/src/fireedge/src/client/components/Tabs/Vm/History/HistoryRecord.js similarity index 79% rename from src/fireedge/src/client/components/Tabs/Vm/History/Item.js rename to src/fireedge/src/client/components/Tabs/Vm/History/HistoryRecord.js index 5ab1f6d4b0..0e9832caee 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/History/Item.js +++ b/src/fireedge/src/client/components/Tabs/Vm/History/HistoryRecord.js @@ -13,17 +13,25 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' import { Folder, User } from 'iconoir-react' import { Typography, Paper } from '@mui/material' import { rowStyles } from 'client/components/Tables/styles' -import * as VirtualMachine from 'client/models/VirtualMachine' -import * as Helper from 'client/models/Helper' +import { getHistoryAction } from 'client/models/VirtualMachine' +import { timeFromMilliseconds, timeDiff } from 'client/models/Helper' +import { HistoryRecord } from 'client/constants' -const HistoryItem = ({ history }) => { +/** + * Renders history record card. + * + * @param {object} props - Props + * @param {HistoryRecord} props.history - History + * @returns {ReactElement} History record card component + */ +const HistoryRecordCard = ({ history }) => { const classes = rowStyles() const { @@ -43,17 +51,17 @@ const HistoryItem = ({ history }) => { const now = Math.round(Date.now() / 1000) - const startTime = Helper.timeFromMilliseconds(+STIME) + const startTime = timeFromMilliseconds(+STIME) const monitorEndTime = +ETIME === 0 ? now : +ETIME - const monitorDiffTime = Helper.timeDiff(+STIME, monitorEndTime) + const monitorDiffTime = timeDiff(+STIME, monitorEndTime) const prologEndTime = +PSTIME === 0 ? 0 : +PETIME === 0 ? now : +PETIME - const prologDiffTime = Helper.timeDiff(+PSTIME, prologEndTime) + const prologDiffTime = timeDiff(+PSTIME, prologEndTime) const ownerInfo = `${UID} | ${GID} | ${REQUEST_ID}` - const action = VirtualMachine.getHistoryAction(+ACTION) + const action = getHistoryAction(+ACTION) return ( @@ -91,11 +99,11 @@ const HistoryItem = ({ history }) => { ) } -HistoryItem.propTypes = { +HistoryRecordCard.propTypes = { history: PropTypes.object.isRequired, actions: PropTypes.arrayOf(PropTypes.string), } -HistoryItem.displayName = 'HistoryItem' +HistoryRecordCard.displayName = 'HistoryRecordCard' -export default HistoryItem +export default HistoryRecordCard diff --git a/src/fireedge/src/client/components/Tabs/Vm/History/index.js b/src/fireedge/src/client/components/Tabs/Vm/History/index.js index 39ea661d3b..738bb92fd5 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/History/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/History/index.js @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext, useMemo } from 'react' +import { ReactElement, useMemo } from 'react' import PropTypes from 'prop-types' -import { TabContext } from 'client/components/Tabs/TabProvider' -import HistoryList from 'client/components/Tabs/Vm/History/List' +import { useGetVmQuery } from 'client/features/OneApi/vm' +import HistoryRecord from 'client/components/Tabs/Vm/History/HistoryRecord' import { getHypervisor, @@ -27,8 +26,17 @@ import { } from 'client/models/VirtualMachine' import { getActionsAvailable } from 'client/models/Helper' -const VmHistoryTab = ({ tabProps: { actions } = {} }) => { - const { data: vm } = useContext(TabContext) +/** + * Renders the list of history records from a VM. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string[]} props.tabProps.actions - Actions tab + * @param {string} props.id - Virtual Machine id + * @returns {ReactElement} History tab + */ +const VmHistoryTab = ({ tabProps: { actions } = {}, id }) => { + const { data: vm = {} } = useGetVmQuery(id) const [records, actionsAvailable] = useMemo(() => { const hypervisor = getHypervisor(vm) @@ -40,11 +48,18 @@ const VmHistoryTab = ({ tabProps: { actions } = {} }) => { return [getHistoryRecords(vm), actionsByState] }, [vm]) - return + return ( +
+ {records.map((history, idx) => ( + + ))} +
+ ) } VmHistoryTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } VmHistoryTab.displayName = 'VmHistoryTab' diff --git a/src/fireedge/src/client/components/Tabs/Vm/Info/index.js b/src/fireedge/src/client/components/Tabs/Vm/Info/index.js index 059de95610..7c7fa6f14d 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Info/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Info/index.js @@ -13,12 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext, useCallback } from 'react' +import { ReactElement, useCallback } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useGetVmQuery, + useChangeVmOwnershipMutation, + useChangeVmPermissionsMutation, + useUpdateUserTemplateMutation, +} from 'client/features/OneApi/vm' import { Permissions, Ownership, @@ -42,7 +46,15 @@ const HIDDEN_ATTRIBUTES_REG = /^(USER_INPUTS|BACKUP|HOT_RESIZE)$|SCHED_|ERROR/ const HIDDEN_MONITORING_REG = /^(CPU|MEMORY|NETTX|NETRX|STATE|DISK_SIZE|SNAPSHOT_SIZE)$/ -const VmInfoTab = ({ tabProps = {} }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Virtual machine id + * @returns {ReactElement} Information tab + */ +const VmInfoTab = ({ tabProps = {}, id }) => { const { information_panel: informationPanel, permissions_panel: permissionsPanel, @@ -53,44 +65,12 @@ const VmInfoTab = ({ tabProps = {} }) => { attributes_panel: attributesPanel, } = tabProps - const { changeOwnership, changePermissions, rename, updateUserTemplate } = - useVmApi() - const { handleRefetch, data: vm = {} } = useContext(TabContext) - const { ID, UNAME, UID, GNAME, GID, PERMISSIONS, USER_TEMPLATE, MONITORING } = - vm + const [changeVmOwnership] = useChangeVmOwnershipMutation() + const [changeVmPermissions] = useChangeVmPermissionsMutation() + const [updateUserTemplate] = useUpdateUserTemplateMutation() + const { data: vm = {} } = useGetVmQuery(id) - const handleChangeOwnership = async (newOwnership) => { - const response = await changeOwnership(ID, newOwnership) - String(response) === String(ID) && (await handleRefetch?.()) - } - - const handleChangePermission = async (newPermission) => { - const response = await changePermissions(ID, newPermission) - String(response) === String(ID) && (await handleRefetch?.()) - } - - const handleRename = async (_, newName) => { - const response = await rename(ID, newName) - String(response) === String(ID) && (await handleRefetch?.()) - } - - const handleAttributeInXml = async (path, newValue) => { - const newTemplate = cloneObject(USER_TEMPLATE) - - set(newTemplate, path, newValue) - - const xml = jsonToXml(newTemplate) - - // 0: Replace the whole user template - const response = await updateUserTemplate(ID, xml, 0) - - String(response) === String(ID) && (await handleRefetch?.()) - } - - const getActions = useCallback( - (actions) => getActionsAvailable(actions, getHypervisor(vm)), - [vm] - ) + const { UNAME, UID, GNAME, GID, PERMISSIONS, USER_TEMPLATE, MONITORING } = vm const { attributes, @@ -108,6 +88,27 @@ const VmInfoTab = ({ tabProps = {} }) => { hidden: HIDDEN_MONITORING_REG, }) + const handleChangeOwnership = async (newOwnership) => { + await changeVmOwnership({ id, ...newOwnership }) + } + + const handleChangePermission = async (newPermission) => { + await changeVmPermissions({ id, ...newPermission }) + } + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(USER_TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await updateUserTemplate({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions, getHypervisor(vm)), + [vm] + ) + const ATTRIBUTE_FUNCTION = { handleAdd: handleAttributeInXml, handleEdit: handleAttributeInXml, @@ -115,24 +116,19 @@ const VmInfoTab = ({ tabProps = {} }) => { } return ( -
{informationPanel?.enabled && ( - + )} {permissionsPanel?.enabled && ( { otherUse={PERMISSIONS.OTHER_U} otherManage={PERMISSIONS.OTHER_M} otherAdmin={PERMISSIONS.OTHER_A} - handleEdit={handleChangePermission} /> )} {ownershipPanel?.enabled && ( )} {attributesPanel?.enabled && attributes && ( @@ -186,12 +181,13 @@ const VmInfoTab = ({ tabProps = {} }) => { title={Tr(T.Monitoring)} /> )} -
+ ) } VmInfoTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } VmInfoTab.displayName = 'VmInfoTab' diff --git a/src/fireedge/src/client/components/Tabs/Vm/Info/information.js b/src/fireedge/src/client/components/Tabs/Vm/Info/information.js index b14f4c654b..45e19ce912 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Info/information.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Info/information.js @@ -13,48 +13,48 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useState } from 'react' +import { ReactElement } from 'react' import PropTypes from 'prop-types' import { generatePath } from 'react-router-dom' -import { useCluster, useClusterApi } from 'client/features/One' +import { useGetClusterQuery } from 'client/features/OneApi/cluster' +import { useRenameVmMutation } from 'client/features/OneApi/vm' + import { StatusChip } from 'client/components/Status' import { List } from 'client/components/Tabs/Common' import MultipleTags from 'client/components/MultipleTags' import { getState, getLastHistory, getIps } from 'client/models/VirtualMachine' import * as Helper from 'client/models/Helper' -import { T, VM_ACTIONS } from 'client/constants' +import { T, VM, VM_ACTIONS } from 'client/constants' import { PATH } from 'client/apps/sunstone/routesOne' -const InformationPanel = ({ vm = {}, handleRename, actions }) => { - const clusters = useCluster() - const { getCluster } = useClusterApi() +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {VM} props.vm - Virtual machine + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ vm = {}, actions }) => { + const [renameVm] = useRenameVmMutation() const { ID, NAME, RESCHED, STIME, ETIME, LOCK, DEPLOY_ID } = vm const { name: stateName, color: stateColor } = getState(vm) + const ips = getIps(vm) const { HID: hostId, HOSTNAME: hostname = '--', CID: clusterId, } = getLastHistory(vm) - const ips = getIps(vm) - const [clusterName, setClusterName] = useState(() => - clusterId === '-1' - ? 'default' - : clusters.find((c) => c.ID === clusterId)?.NAME - ) + const { data: cluster } = useGetClusterQuery({ id: clusterId }) + const clusterName = +clusterId === -1 ? 'default' : cluster?.NAME ?? '--' - useEffect(() => { - const loadCluster = async () => { - const cluster = await getCluster(clusterId) - cluster?.NAME && setClusterName(cluster.NAME) - } - - !clusterName && loadCluster() - }, []) + const handleRename = async (_, newName) => { + await renameVm({ id: ID, name: newName }) + } const info = [ { @@ -72,7 +72,7 @@ const InformationPanel = ({ vm = {}, handleRename, actions }) => { { name: T.State, value: ( - + ), }, { @@ -110,7 +110,7 @@ const InformationPanel = ({ vm = {}, handleRename, actions }) => { }, clusterId && { name: T.Cluster, - value: clusterName ? `#${clusterId} ${clusterName}` : `#${clusterId} --`, + value: `#${clusterId} ${clusterName}`, link: !Number.isNaN(+clusterId) && generatePath(PATH.INFRASTRUCTURE.CLUSTERS.DETAIL, { id: clusterId }), @@ -132,12 +132,11 @@ const InformationPanel = ({ vm = {}, handleRename, actions }) => { ) } -InformationPanel.displayName = 'InformationPanel' - InformationPanel.propTypes = { actions: PropTypes.arrayOf(PropTypes.string), - handleRename: PropTypes.func, vm: PropTypes.object, } +InformationPanel.displayName = 'InformationPanel' + export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/Vm/Log.js b/src/fireedge/src/client/components/Tabs/Vm/Log.js deleted file mode 100644 index 12d2e7d427..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/Log.js +++ /dev/null @@ -1,26 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ - -const VmLogTab = (data) => ( -
-

WIP - LOG

-
-) - -VmLogTab.displayName = 'VmLogTab' - -export default VmLogTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/Actions.js b/src/fireedge/src/client/components/Tabs/Vm/Network/Actions.js new file mode 100644 index 0000000000..becbd9edd9 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Vm/Network/Actions.js @@ -0,0 +1,107 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { memo } from 'react' +import PropTypes from 'prop-types' +import { Trash } from 'iconoir-react' + +import { + useAttachNicMutation, + useDetachNicMutation, +} from 'client/features/OneApi/vm' +import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm' +import { AttachNicForm } from 'client/components/Forms/Vm' + +import { jsonToXml } from 'client/models/Helper' +import { Tr, Translate } from 'client/components/HOC' +import { T } from 'client/constants' + +const AttachAction = memo(({ vmId, currentNics }) => { + const [attachNic] = useAttachNicMutation() + + const handleAttachNic = async (formData) => { + const isAlias = !!formData?.PARENT?.length + const data = { [isAlias ? 'NIC_ALIAS' : 'NIC']: formData } + + const template = jsonToXml(data) + await attachNic({ id: vmId, template }) + } + + return ( + AttachNicForm({ nics: currentNics }), + onSubmit: handleAttachNic, + }, + ]} + /> + ) +}) + +const DetachAction = memo(({ vmId, nic }) => { + const [detachNic] = useDetachNicMutation() + const { NIC_ID, PARENT } = nic + const isAlias = !!PARENT?.length + + const handleDetach = async () => { + await detachNic({ id: vmId, nic: NIC_ID }) + } + + return ( + , + tooltip: Tr(T.Detach), + }} + options={[ + { + isConfirmDialog: true, + dialogProps: { + title: ( + + ), + children:

{Tr(T.DoYouWantProceed)}

, + }, + onSubmit: handleDetach, + }, + ]} + /> + ) +}) + +const ActionPropTypes = { + vmId: PropTypes.string.isRequired, + currentNics: PropTypes.object, + nic: PropTypes.object, +} + +AttachAction.propTypes = ActionPropTypes +AttachAction.displayName = 'AttachActionButton' +DetachAction.propTypes = ActionPropTypes +DetachAction.displayName = 'DetachActionButton' + +export { AttachAction, DetachAction } diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/Alias.js b/src/fireedge/src/client/components/Tabs/Vm/Network/Alias.js deleted file mode 100644 index 89d1b581cc..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/Network/Alias.js +++ /dev/null @@ -1,90 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { memo } from 'react' -import PropTypes from 'prop-types' - -import { styled, useMediaQuery } from '@mui/material' -import Typography from '@mui/material/Typography' - -import MultipleTags from 'client/components/MultipleTags' - -import { Translate } from 'client/components/HOC' -import { T } from 'client/constants' - -const DATACY_ALIAS = 'alias-' - -const Row = styled('div')({ - display: 'flex', - width: '100%', - gap: '0.5em', - alignItems: 'center', - flexWrap: 'nowrap', -}) - -const Labels = styled('span')({ - display: 'inline-flex', - gap: '0.5em', - alignItems: 'center', -}) - -const Alias = memo(({ alias, isPciDevice, detachAction }) => { - const isMobile = useMediaQuery((theme) => theme.breakpoints.down('md')) - const { NIC_ID, NETWORK, IP, MAC, BRIDGE } = alias - - const tags = [ - { - text: IP, - dataCy: `${DATACY_ALIAS}ip`, - }, - { - text: MAC, - dataCy: `${DATACY_ALIAS}mac`, - }, - { - text: BRIDGE && `BRIDGE - ${BRIDGE}`, - dataCy: `${DATACY_ALIAS}bridge`, - }, - ].filter(({ text } = {}) => Boolean(text)) - - return ( - - - - {`${NIC_ID} | ${NETWORK}`} - - - - - {!isMobile && !isPciDevice && detachAction(NIC_ID, true)} - - ) -}) - -Alias.displayName = 'Alias' - -Alias.propTypes = { - alias: PropTypes.shape({ - NIC_ID: PropTypes.string, - NETWORK: PropTypes.string, - IP: PropTypes.string, - MAC: PropTypes.string, - BRIDGE: PropTypes.string, - }), - isPciDevice: PropTypes.bool, - detachAction: PropTypes.func, -} - -export default Alias diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/Item.js b/src/fireedge/src/client/components/Tabs/Vm/Network/Item.js deleted file mode 100644 index ba05f63e1b..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/Network/Item.js +++ /dev/null @@ -1,222 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useMemo, useContext } from 'react' -import PropTypes from 'prop-types' - -import { styled, useMediaQuery } from '@mui/material' -import Typography from '@mui/material/Typography' -import Paper from '@mui/material/Paper' -import MAccordion from '@mui/material/Accordion' -import AccordionDetails from '@mui/material/AccordionDetails' -import AccordionSummary, { - accordionSummaryClasses, -} from '@mui/material/AccordionSummary' -import { Trash as TrashIcon, NavArrowRight as ExpandIcon } from 'iconoir-react' - -import { useVmApi } from 'client/features/One' -import { useDialog } from 'client/hooks' -import { TabContext } from 'client/components/Tabs/TabProvider' -import { Action } from 'client/components/Cards/SelectCard' -import { DialogConfirmation } from 'client/components/Dialogs' -import MultipleTags from 'client/components/MultipleTags' -import Alias from 'client/components/Tabs/Vm/Network/Alias' -import SecGroup from 'client/components/Tabs/Vm/Network/SecGroup' - -import { Translate } from 'client/components/HOC' -import { T, VM_ACTIONS } from 'client/constants' - -const DATACY_NETWORK = 'network-' - -const Accordion = styled((props) => ( - -))(({ theme }) => ({ - border: `1px solid ${theme.palette.divider}`, - '&:before': { display: 'none' }, -})) - -const Summary = styled(AccordionSummary)({ - [`&.${accordionSummaryClasses.root}`]: { - backgroundColor: 'rgba(0, 0, 0, .03)', - flexDirection: 'row-reverse', - '&:hover': { backgroundColor: 'rgba(0, 0, 0, .07)' }, - }, - [`& .${accordionSummaryClasses.expandIconWrapper}.${accordionSummaryClasses.expanded}`]: - { - transform: 'rotate(90deg)', - }, -}) - -const Row = styled('div')({ - display: 'flex', - width: '100%', - gap: '0.5em', - alignItems: 'center', - flexWrap: 'nowrap', -}) - -const Labels = styled('span')({ - display: 'inline-flex', - gap: '0.5em', - alignItems: 'center', -}) - -const Details = styled(AccordionDetails)({ - display: 'flex', - flexDirection: 'column', - gap: '0.5em', - marginLeft: '1em', -}) - -const SecGroups = styled(Paper)({ - display: 'flex', - flexDirection: 'column', - gap: '0.5em', - padding: '0.8em', -}) - -const NetworkItem = ({ nic = {}, actions }) => { - const isMobile = useMediaQuery((theme) => theme.breakpoints.down('md')) - - const { display, show, hide, values } = useDialog() - const { detachNic } = useVmApi() - const { handleRefetch, data: vm } = useContext(TabContext) - - const { - NIC_ID, - NETWORK = '-', - IP, - MAC, - PCI_ID, - ADDRESS, - ALIAS, - SECURITY_GROUPS, - } = nic - const isPciDevice = PCI_ID !== undefined - - const hasDetails = useMemo( - () => !!ALIAS.length || !!SECURITY_GROUPS?.length, - [ALIAS?.length, SECURITY_GROUPS?.length] - ) - - const handleDetach = async () => { - const response = - values?.id !== undefined && (await detachNic(vm.ID, values.id)) - - String(response) === String(vm.ID) && (await handleRefetch?.(vm.ID)) - hide() - } - - const detachAction = (id, isAlias) => - actions?.includes?.(VM_ACTIONS.DETACH_NIC) && ( - } - stopPropagation - handleClick={() => show({ id, isAlias })} - /> - ) - - const tags = [ - { - text: IP, - dataCy: `${DATACY_NETWORK}ip`, - }, - { - text: MAC, - dataCy: `${DATACY_NETWORK}mac`, - }, - { - text: ADDRESS, - dataCy: `${DATACY_NETWORK}address`, - }, - ].filter(({ text } = {}) => Boolean(text)) - - return ( - <> - - })}> - - - {`${NIC_ID} | ${NETWORK}`} - - - - - {!isMobile && !isPciDevice && detachAction(NIC_ID)} - - - {hasDetails && ( -
- {ALIAS?.map((alias) => ( - - ))} - {!!SECURITY_GROUPS?.length && ( - - - - - - {SECURITY_GROUPS?.map((securityGroup, idx) => ( - - ))} - - )} -
- )} -
- - {display && ( - - } - handleAccept={handleDetach} - handleCancel={hide} - > - - - - - )} - - ) -} - -NetworkItem.propTypes = { - actions: PropTypes.arrayOf(PropTypes.string), - nic: PropTypes.object, -} - -NetworkItem.displayName = 'NetworkItem' - -export default NetworkItem diff --git a/src/fireedge/src/client/components/Tabs/Vm/Network/index.js b/src/fireedge/src/client/components/Tabs/Vm/Network/index.js index c037def443..efc4870667 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Network/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Network/index.js @@ -13,29 +13,38 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext, useMemo } from 'react' +import { ReactElement, useMemo } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' - -import NetworkList from 'client/components/Tabs/Vm/Network/List' -import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm' -import { AttachNicForm } from 'client/components/Forms/Vm' +import { useGetVmQuery } from 'client/features/OneApi/vm' +import NicCard from 'client/components/Cards/NicCard' +import { + AttachAction, + DetachAction, +} from 'client/components/Tabs/Vm/Network/Actions' import { getNics, getHypervisor, isAvailableAction, } from 'client/models/VirtualMachine' -import { jsonToXml, getActionsAvailable } from 'client/models/Helper' -import { T, VM_ACTIONS } from 'client/constants' +import { getActionsAvailable } from 'client/models/Helper' +import { VM_ACTIONS } from 'client/constants' -const VmNetworkTab = ({ tabProps: { actions } = {} }) => { - const { attachNic } = useVmApi() +const { ATTACH_NIC, DETACH_NIC } = VM_ACTIONS - const { handleRefetch, data: vm } = useContext(TabContext) +/** + * Renders the list of networks from a VM. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string[]} props.tabProps.actions - Actions tab + * @param {string} props.id - Virtual Machine id + * @returns {ReactElement} Networks tab + */ +const VmNetworkTab = ({ tabProps: { actions } = {}, id }) => { + const { data: vm } = useGetVmQuery(id) const [nics, actionsAvailable] = useMemo(() => { const groupedNics = getNics(vm, { @@ -51,43 +60,36 @@ const VmNetworkTab = ({ tabProps: { actions } = {} }) => { return [groupedNics, actionsByState] }, [vm]) - const handleAttachNic = async (formData) => { - const isAlias = !!formData?.PARENT?.length - const data = { [isAlias ? 'NIC_ALIAS' : 'NIC']: formData } - - const template = jsonToXml(data) - const response = await attachNic(vm.ID, template) - - String(response) === String(vm.ID) && (await handleRefetch?.(vm.ID)) - } - return ( <> - {actionsAvailable?.includes?.(VM_ACTIONS.ATTACH_NIC) && ( - AttachNicForm({ nics }), - onSubmit: handleAttachNic, - }, - ]} - /> + {actionsAvailable?.includes?.(ATTACH_NIC) && ( + )} - + + {nics.map((nic) => { + const { IP, MAC, ADDRESS } = nic + const key = IP ?? MAC ?? ADDRESS // address only exists form PCI nics + + return ( + + ) + })} + ) } VmNetworkTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } VmNetworkTab.displayName = 'VmNetworkTab' diff --git a/src/fireedge/src/client/components/Tabs/Vm/SchedActions.js b/src/fireedge/src/client/components/Tabs/Vm/SchedActions.js index c5c9fdd345..4c3deb621e 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/SchedActions.js +++ b/src/fireedge/src/client/components/Tabs/Vm/SchedActions.js @@ -13,17 +13,23 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { ReactElement, useContext, useMemo } from 'react' +import { ReactElement, useMemo } from 'react' import PropTypes from 'prop-types' import { Stack } from '@mui/material' -import { useAuth } from 'client/features/Auth' -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { useGetSunstoneConfigQuery } from 'client/features/OneApi/system' +import { + useGetVmQuery, + useAddScheduledActionMutation, + useUpdateScheduledActionMutation, + useDeleteScheduledActionMutation, +} from 'client/features/OneApi/vm' import ScheduleActionCard from 'client/components/Cards/ScheduleActionCard' import { CreateSchedButton, CharterButton, + UpdateSchedButton, + DeleteSchedButton, } from 'client/components/Buttons/ScheduleAction' import { @@ -42,19 +48,20 @@ const { } = VM_ACTIONS /** - * Renders the list of schedule action from a VM. + * Renders the list of schedule actions from a VM. * * @param {object} props - Props * @param {object|boolean} props.tabProps - Tab properties * @param {object} [props.tabProps.actions] - Actions from user view yaml - * @returns {ReactElement} List of schedule actions + * @param {string} props.id - Virtual Machine id + * @returns {ReactElement} Schedule actions tab */ -const VmSchedulingTab = ({ tabProps: { actions } = {} }) => { - const { config } = useAuth() - const { handleRefetch, data: vm } = useContext(TabContext) - - const { addScheduledAction, updateScheduledAction, deleteScheduledAction } = - useVmApi() +const VmSchedulingTab = ({ tabProps: { actions } = {}, id }) => { + const { data: config } = useGetSunstoneConfigQuery() + const [addScheduledAction] = useAddScheduledActionMutation() + const [updateScheduledAction] = useUpdateScheduledActionMutation() + const [deleteScheduledAction] = useDeleteScheduledActionMutation() + const { data: vm = {} } = useGetVmQuery(id) const [scheduling, actionsAvailable] = useMemo(() => { const hypervisor = getHypervisor(vm) @@ -66,7 +73,7 @@ const VmSchedulingTab = ({ tabProps: { actions } = {} }) => { return [getScheduleActions(vm), actionsByState] }, [vm]) - const iCreateEnabled = actionsAvailable?.includes?.(SCHED_ACTION_CREATE) + const isCreateEnabled = actionsAvailable?.includes?.(SCHED_ACTION_CREATE) const isUpdateEnabled = actionsAvailable?.includes?.(SCHED_ACTION_UPDATE) const isDeleteEnabled = actionsAvailable?.includes?.(SCHED_ACTION_DELETE) const isCharterEnabled = @@ -79,41 +86,30 @@ const VmSchedulingTab = ({ tabProps: { actions } = {} }) => { * @returns {Promise} - Add schedule action and refetch VM data */ const handleCreateSchedAction = async (formData) => { - const data = { template: jsonToXml({ SCHED_ACTION: formData }) } - const response = await addScheduledAction(vm.ID, data) - - String(response) === String(vm.ID) && (await handleRefetch?.(vm.ID)) + const template = jsonToXml({ SCHED_ACTION: formData }) + await addScheduledAction({ id, template }) } /** * Update schedule action to VM. * * @param {object} formData - Updated schedule action - * @param {string|number} id - Schedule action id + * @param {string|number} schedId - Schedule action id * @returns {Promise} - Update schedule action and refetch VM data */ - const handleUpdate = async (formData, id) => { - const data = { - id_sched: id, - template: jsonToXml({ SCHED_ACTION: formData }), - } - - const response = await updateScheduledAction(vm.ID, data) - - String(response) === String(vm.ID) && (await handleRefetch?.(vm.ID)) + const handleUpdate = async (formData, schedId) => { + const template = jsonToXml({ SCHED_ACTION: formData }) + await updateScheduledAction({ id, schedId, template }) } /** * Delete schedule action to VM. * - * @param {string|number} id - Schedule action id + * @param {string|number} schedId - Schedule action id * @returns {Promise} - Delete schedule action and refetch VM data */ - const handleRemove = async (id) => { - const data = { id_sched: id } - const response = await deleteScheduledAction(vm.ID, data) - - String(response) === String(vm.ID) && (await handleRefetch?.(vm.ID)) + const handleRemove = async (schedId) => { + await deleteScheduledAction({ id, schedId }) } /** @@ -123,42 +119,45 @@ const VmSchedulingTab = ({ tabProps: { actions } = {} }) => { * @returns {Promise} - Add schedule actions and refetch VM data */ const handleCreateCharter = async (formData) => { - const responses = await Promise.all( - formData.map((schedAction) => { - const data = { template: jsonToXml({ SCHED_ACTION: schedAction }) } - - return addScheduledAction(vm.ID, data) - }) - ) - - responses.some((response) => String(response) === String(vm?.ID)) && - (await handleRefetch?.(vm.ID)) + await Promise.all(formData.map(addScheduledAction)) } return ( <> - {(iCreateEnabled || isCharterEnabled) && ( + {(isCreateEnabled || isCharterEnabled) && ( - {iCreateEnabled && ( + {isCreateEnabled && ( )} {isCharterEnabled && } )} - + {scheduling.map((schedule) => { const { ID, NAME } = schedule return ( handleUpdate(newAction, ID), - })} - {...(isDeleteEnabled && { handleRemove: () => handleRemove(ID) })} + actions={({ noMore }) => ( + <> + {isUpdateEnabled && !noMore && ( + handleUpdate(newAction, ID)} + /> + )} + {isDeleteEnabled && ( + handleRemove(ID)} + schedule={schedule} + /> + )} + + )} /> ) })} @@ -168,11 +167,8 @@ const VmSchedulingTab = ({ tabProps: { actions } = {} }) => { } VmSchedulingTab.propTypes = { - tabProps: PropTypes.shape({ - actions: PropTypes.object, - }), + tabProps: PropTypes.object, + id: PropTypes.string, } -VmSchedulingTab.displayName = 'VmSchedulingTab' - export default VmSchedulingTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/Actions.js b/src/fireedge/src/client/components/Tabs/Vm/Snapshot/Actions.js index 3f559e58cb..7425bbbec9 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/Actions.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Snapshot/Actions.js @@ -13,25 +13,54 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useContext } from 'react' +import { memo } from 'react' import PropTypes from 'prop-types' import { Trash, UndoAction } from 'iconoir-react' - -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useCreateVmSnapshotMutation, + useRevertVmSnapshotMutation, + useDeleteVmSnapshotMutation, +} from 'client/features/OneApi/vm' import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm' +import { CreateSnapshotForm } from 'client/components/Forms/Vm' import { Tr, Translate } from 'client/components/HOC' import { T, VM_ACTIONS } from 'client/constants' -const RevertAction = memo(({ snapshot }) => { - const { SNAPSHOT_ID, NAME } = snapshot - const { revertSnapshot } = useVmApi() - const { data: vm } = useContext(TabContext) +const CreateAction = memo(({ vmId }) => { + const [createSnapshot] = useCreateVmSnapshotMutation() - const handleRevert = async () => await revertSnapshot(vm.ID, SNAPSHOT_ID) + const handleCreate = async ({ name } = {}) => { + await createSnapshot({ id: vmId, name }) + } + + return ( + CreateSnapshotForm(), + onSubmit: handleCreate, + }, + ]} + /> + ) +}) + +const RevertAction = memo(({ vmId, snapshot }) => { + const [revertSnapshot] = useRevertVmSnapshotMutation() + const { SNAPSHOT_ID, NAME } = snapshot + + const handleRevert = async () => { + await revertSnapshot({ id: vmId, snapshot: SNAPSHOT_ID }) + } return ( { ) }) -const DeleteAction = memo(({ snapshot }) => { +const DeleteAction = memo(({ vmId, snapshot }) => { + const [deleteSnapshot] = useDeleteVmSnapshotMutation() const { SNAPSHOT_ID, NAME } = snapshot - const { deleteSnapshot } = useVmApi() - const { data: vm } = useContext(TabContext) - const handleDelete = async () => await deleteSnapshot(vm.ID, SNAPSHOT_ID) + const handleDelete = async () => { + await deleteSnapshot({ id: vmId, snapshot: SNAPSHOT_ID }) + } return ( { }) const ActionPropTypes = { + vmId: PropTypes.string.isRequired, snapshot: PropTypes.object, - name: PropTypes.string, } +CreateAction.propTypes = ActionPropTypes +CreateAction.displayName = 'CreateActionButton' RevertAction.propTypes = ActionPropTypes RevertAction.displayName = 'RevertActionButton' DeleteAction.propTypes = ActionPropTypes DeleteAction.displayName = 'DeleteActionButton' -export { DeleteAction, RevertAction } +export { CreateAction, DeleteAction, RevertAction } diff --git a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/index.js b/src/fireedge/src/client/components/Tabs/Vm/Snapshot/index.js index 8673881378..60878af4e2 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Snapshot/index.js @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext, useMemo } from 'react' +import { ReactElement, useMemo } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' - -import SnapshotList from 'client/components/Tabs/Vm/Snapshot/List' -import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm' -import { CreateSnapshotForm } from 'client/components/Forms/Vm' +import { useGetVmQuery } from 'client/features/OneApi/vm' +import { + CreateAction, + RevertAction, + DeleteAction, +} from 'client/components/Tabs/Vm/Snapshot/Actions' +import SnapshotCard from 'client/components/Cards/SnapshotCard' import { getSnapshotList, @@ -30,12 +31,21 @@ import { isAvailableAction, } from 'client/models/VirtualMachine' import { getActionsAvailable } from 'client/models/Helper' -import { T, VM_ACTIONS } from 'client/constants' +import { VM_ACTIONS } from 'client/constants' -const VmSnapshotTab = ({ tabProps: { actions } = {} }) => { - const { createSnapshot } = useVmApi() +const { SNAPSHOT_CREATE, SNAPSHOT_REVERT, SNAPSHOT_DELETE } = VM_ACTIONS - const { data: vm = {} } = useContext(TabContext) +/** + * Renders the list of snapshots from a VM. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string[]} props.tabProps.actions - Actions tab + * @param {string} props.id - Virtual Machine id + * @returns {ReactElement} Snapshots tab + */ +const VmSnapshotTab = ({ tabProps: { actions } = {}, id }) => { + const { data: vm = {} } = useGetVmQuery(id) const [snapshots, actionsAvailable] = useMemo(() => { const hypervisor = getHypervisor(vm) @@ -47,37 +57,31 @@ const VmSnapshotTab = ({ tabProps: { actions } = {} }) => { return [getSnapshotList(vm), actionsByState] }, [vm]) - const handleSnapshotCreate = async (formData = {}) => { - await createSnapshot(vm.ID, formData) - } - return ( <> - {actionsAvailable?.includes?.(VM_ACTIONS.SNAPSHOT_CREATE) && ( - CreateSnapshotForm(), - onSubmit: handleSnapshotCreate, - }, - ]} - /> + {actionsAvailable?.includes(SNAPSHOT_CREATE) && ( + )} - + + {snapshots.map((snapshot) => ( + + ))} + ) } VmSnapshotTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } VmSnapshotTab.displayName = 'VmSnapshotTab' diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/Actions.js b/src/fireedge/src/client/components/Tabs/Vm/Storage/Actions.js index 5880b02931..6237f2877e 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Storage/Actions.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Storage/Actions.js @@ -13,8 +13,7 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useContext } from 'react' +import { memo } from 'react' import PropTypes from 'prop-types' import { @@ -26,24 +25,72 @@ import { Expand, } from 'iconoir-react' -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useAttachDiskMutation, + useDetachDiskMutation, + useSaveAsDiskMutation, + useResizeDiskMutation, + useCreateDiskSnapshotMutation, + useRenameDiskSnapshotMutation, + useRevertDiskSnapshotMutation, + useDeleteDiskSnapshotMutation, +} from 'client/features/OneApi/vm' import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm' import { + ImageSteps, + VolatileSteps, SaveAsDiskForm, CreateDiskSnapshotForm, ResizeDiskForm, } from 'client/components/Forms/Vm' +import { jsonToXml } from 'client/models/Helper' import { Tr, Translate } from 'client/components/HOC' import { T, VM_ACTIONS } from 'client/constants' -const DetachAction = memo(({ disk, name: imageName }) => { - const { DISK_ID } = disk - const { detachDisk } = useVmApi() - const { data: vm } = useContext(TabContext) +const AttachAction = memo(({ vmId, hypervisor }) => { + const [attachDisk] = useAttachDiskMutation() - const handleDetach = async () => await detachDisk(vm.ID, DISK_ID) + const handleAttachDisk = async (formData) => { + const template = jsonToXml({ DISK: formData }) + await attachDisk({ id: vmId, template }) + } + + return ( + ImageSteps({ hypervisor }), + onSubmit: handleAttachDisk, + }, + { + cy: 'attach-volatile', + name: T.Volatile, + dialogProps: { title: T.AttachVolatile }, + form: () => VolatileSteps({ hypervisor }), + onSubmit: handleAttachDisk, + }, + ]} + /> + ) +}) + +const DetachAction = memo(({ vmId, disk, name: imageName }) => { + const [detachDisk] = useDetachDiskMutation() + const { DISK_ID } = disk + + const handleDetach = async () => { + await detachDisk({ id: vmId, disk: DISK_ID }) + } return ( { ) }) -const SaveAsAction = memo(({ disk, snapshot, name: imageName }) => { +const SaveAsAction = memo(({ vmId, disk, snapshot, name: imageName }) => { + const [saveAsDisk] = useSaveAsDiskMutation() const { DISK_ID: diskId } = disk const { ID: snapshotId, NAME: snapshotName } = snapshot ?? {} - const { saveAsDisk } = useVmApi() - const { handleRefetch, data: vm } = useContext(TabContext) - const handleSaveAs = async ({ NAME } = {}) => { - const data = { disk: diskId, name: NAME, snapshot: snapshotId } - const response = await saveAsDisk(vm.ID, data) - - String(response) === String(vm.ID) && (await handleRefetch?.(vm.ID)) + await saveAsDisk({ + id: vmId, + disk: diskId, + name: NAME, + snapshot: snapshotId, + }) } return ( @@ -116,14 +163,12 @@ const SaveAsAction = memo(({ disk, snapshot, name: imageName }) => { ) }) -const ResizeAction = memo(({ disk, name: imageName }) => { +const ResizeAction = memo(({ vmId, disk, name: imageName }) => { + const [resizeDisk] = useResizeDiskMutation() const { DISK_ID } = disk - const { resizeDisk } = useVmApi() - const { data: vm } = useContext(TabContext) const handleResize = async ({ SIZE } = {}) => { - const data = { disk: DISK_ID, size: SIZE } - await resizeDisk(vm.ID, data) + await resizeDisk({ id: vmId, disk: DISK_ID, size: SIZE }) } return ( @@ -151,14 +196,12 @@ const ResizeAction = memo(({ disk, name: imageName }) => { ) }) -const SnapshotCreateAction = memo(({ disk, name: imageName }) => { +const SnapshotCreateAction = memo(({ vmId, disk, name: imageName }) => { + const [createDiskSnapshot] = useCreateDiskSnapshotMutation() const { DISK_ID } = disk - const { createDiskSnapshot } = useVmApi() - const { data: vm } = useContext(TabContext) const handleSnapshotCreate = async ({ NAME } = {}) => { - const data = { disk: DISK_ID, name: NAME } - await createDiskSnapshot(vm.ID, data) + await createDiskSnapshot({ id: vmId, disk: DISK_ID, name: NAME }) } return ( @@ -186,17 +229,18 @@ const SnapshotCreateAction = memo(({ disk, name: imageName }) => { ) }) -const SnapshotRenameAction = memo(({ disk, snapshot }) => { +const SnapshotRenameAction = memo(({ vmId, disk, snapshot }) => { + const [renameDiskSnapshot] = useRenameDiskSnapshotMutation() const { DISK_ID } = disk const { ID, NAME = '' } = snapshot - const { renameDiskSnapshot } = useVmApi() - const { handleRefetch, data: vm } = useContext(TabContext) const handleRename = async ({ NAME: newName } = {}) => { - const data = { disk: DISK_ID, snapshot: ID, name: newName } - const response = await renameDiskSnapshot(vm.ID, data) - - String(response) === String(vm.ID) && (await handleRefetch?.(vm.ID)) + await renameDiskSnapshot({ + id: vmId, + disk: DISK_ID, + snapshot: ID, + name: newName, + }) } return ( @@ -222,15 +266,13 @@ const SnapshotRenameAction = memo(({ disk, snapshot }) => { ) }) -const SnapshotRevertAction = memo(({ disk, snapshot }) => { +const SnapshotRevertAction = memo(({ vmId, disk, snapshot }) => { + const [revertDiskSnapshot] = useRevertDiskSnapshotMutation() const { DISK_ID } = disk const { ID, NAME = T.Snapshot } = snapshot - const { revertDiskSnapshot } = useVmApi() - const { data: vm } = useContext(TabContext) const handleRevert = async () => { - const data = { disk: DISK_ID, snapshot: ID } - await revertDiskSnapshot(vm.ID, data) + await revertDiskSnapshot({ id: vmId, disk: DISK_ID, snapshot: ID }) } return ( @@ -256,15 +298,13 @@ const SnapshotRevertAction = memo(({ disk, snapshot }) => { ) }) -const SnapshotDeleteAction = memo(({ disk, snapshot }) => { +const SnapshotDeleteAction = memo(({ vmId, disk, snapshot }) => { + const [deleteDiskSnapshot] = useDeleteDiskSnapshotMutation() const { DISK_ID } = disk const { ID, NAME = T.Snapshot } = snapshot - const { deleteDiskSnapshot } = useVmApi() - const { data: vm } = useContext(TabContext) const handleDelete = async () => { - const data = { disk: DISK_ID, snapshot: ID } - await deleteDiskSnapshot(vm.ID, data) + await deleteDiskSnapshot({ id: vmId, disk: DISK_ID, snapshot: ID }) } return ( @@ -291,11 +331,15 @@ const SnapshotDeleteAction = memo(({ disk, snapshot }) => { }) const ActionPropTypes = { + vmId: PropTypes.string.isRequired, + hypervisor: PropTypes.string, disk: PropTypes.object, snapshot: PropTypes.object, name: PropTypes.string, } +AttachAction.propTypes = ActionPropTypes +AttachAction.displayName = 'AttachActionButton' DetachAction.propTypes = ActionPropTypes DetachAction.displayName = 'DetachActionButton' SaveAsAction.propTypes = ActionPropTypes @@ -312,6 +356,7 @@ SnapshotDeleteAction.propTypes = ActionPropTypes SnapshotDeleteAction.displayName = 'SnapshotDeleteActionButton' export { + AttachAction, DetachAction, SaveAsAction, ResizeAction, diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/Item.js b/src/fireedge/src/client/components/Tabs/Vm/Storage/Item.js deleted file mode 100644 index e357e3556e..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/Storage/Item.js +++ /dev/null @@ -1,168 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import PropTypes from 'prop-types' - -import { DatabaseSettings, Folder, ModernTv } from 'iconoir-react' -import { Typography, Paper } from '@mui/material' - -import * as Actions from 'client/components/Tabs/Vm/Storage/Actions' -import StorageSubItem from 'client/components/Tabs/Vm/Storage/SubItem' -import { StatusChip } from 'client/components/Status' -import { rowStyles } from 'client/components/Tables/styles' - -import * as Helper from 'client/models/Helper' -import { prettyBytes } from 'client/utils' -import { VM_ACTIONS } from 'client/constants' - -const StorageItem = ({ disk, actions = [] }) => { - const classes = rowStyles() - - const { - DISK_ID, - DATASTORE, - TARGET, - IMAGE, - IMAGE_ID, - TYPE, - FORMAT, - SIZE, - MONITOR_SIZE, - READONLY, - PERSISTENT, - SAVE, - CLONE, - IS_CONTEXT, - SNAPSHOTS, - } = disk - - const size = +SIZE ? prettyBytes(+SIZE, 'MB') : '-' - const monitorSize = +MONITOR_SIZE ? prettyBytes(+MONITOR_SIZE, 'MB') : '-' - - const isImage = IMAGE_ID !== undefined - const type = String(TYPE).toLowerCase() - - const image = - IMAGE ?? - { - fs: `${FORMAT} - ${size}`, - swap: size, - }[type] - - const labels = [ - { - label: TYPE, - dataCy: 'type', - }, - { - label: Helper.stringToBoolean(PERSISTENT) && 'PERSISTENT', - dataCy: 'persistent', - }, - { - label: Helper.stringToBoolean(READONLY) && 'READONLY', - dataCy: 'readonly', - }, - { - label: Helper.stringToBoolean(SAVE) && 'SAVE', - dataCy: 'save', - }, - { - label: Helper.stringToBoolean(CLONE) && 'CLONE', - dataCy: 'clone', - }, - ].filter(({ label } = {}) => Boolean(label)) - - return ( - -
-
- - {image} - - - {labels.map(({ label, dataCy }) => ( - - ))} - -
-
- {`#${DISK_ID}`} - {TARGET && ( - - - {` ${TARGET}`} - - )} - {DATASTORE && ( - - - {` ${DATASTORE}`} - - )} - - - {` ${monitorSize}/${size}`} - -
-
- {!IS_CONTEXT && !!actions.length && ( -
- {actions?.includes?.(VM_ACTIONS.DISK_SAVEAS) && isImage && ( - - )} - {actions?.includes?.(VM_ACTIONS.SNAPSHOT_DISK_CREATE) && isImage && ( - - )} - {actions?.includes?.(VM_ACTIONS.RESIZE_DISK) && ( - - )} - {actions?.includes?.(VM_ACTIONS.DETACH_DISK) && ( - - )} -
- )} - {SNAPSHOTS?.length > 0 && ( -
- {SNAPSHOTS?.map((snapshot) => ( - - ))} -
- )} -
- ) -} - -StorageItem.propTypes = { - disk: PropTypes.object.isRequired, - actions: PropTypes.arrayOf(PropTypes.string), -} - -StorageItem.displayName = 'StorageItem' - -export default StorageItem diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/SubItem.js b/src/fireedge/src/client/components/Tabs/Vm/Storage/SubItem.js deleted file mode 100644 index 7032da826e..0000000000 --- a/src/fireedge/src/client/components/Tabs/Vm/Storage/SubItem.js +++ /dev/null @@ -1,99 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import PropTypes from 'prop-types' -import { ModernTv } from 'iconoir-react' -import { Typography, Paper } from '@mui/material' - -import * as Actions from 'client/components/Tabs/Vm/Storage/Actions' -import { StatusChip } from 'client/components/Status' -import { rowStyles } from 'client/components/Tables/styles' -import { Translate } from 'client/components/HOC' - -import * as Helper from 'client/models/Helper' -import { prettyBytes } from 'client/utils' -import { T, VM_ACTIONS } from 'client/constants' - -const StorageSubItem = ({ disk, snapshot = {}, actions = [] }) => { - const classes = rowStyles() - - const isImage = disk?.IMAGE_ID !== undefined - - const { - ID, - NAME, - ACTIVE, - DATE, - SIZE: SNAPSHOT_SIZE, - MONITOR_SIZE: SNAPSHOT_MONITOR_SIZE, - } = snapshot - - const isActive = Helper.stringToBoolean(ACTIVE) - const time = Helper.timeFromMilliseconds(+DATE) - const timeAgo = `created ${time.toRelative()}` - - const size = +SNAPSHOT_SIZE ? prettyBytes(+SNAPSHOT_SIZE, 'MB') : '-' - const monitorSize = +SNAPSHOT_MONITOR_SIZE - ? prettyBytes(+SNAPSHOT_MONITOR_SIZE, 'MB') - : '-' - - return ( - -
-
- {NAME} - - {isActive && } />} - } /> - -
-
- {`#${ID} ${timeAgo}`} - - - {` ${monitorSize}/${size}`} - -
-
- {!!actions.length && ( -
- {actions?.includes?.(VM_ACTIONS.DISK_SAVEAS) && isImage && ( - - )} - {actions?.includes?.(VM_ACTIONS.SNAPSHOT_DISK_RENAME) && ( - - )} - {actions?.includes?.(VM_ACTIONS.SNAPSHOT_DISK_REVERT) && ( - - )} - {actions?.includes?.(VM_ACTIONS.SNAPSHOT_DISK_DELETE) && ( - - )} -
- )} -
- ) -} - -StorageSubItem.propTypes = { - disk: PropTypes.object.isRequired, - snapshot: PropTypes.object.isRequired, - actions: PropTypes.arrayOf(PropTypes.string), -} - -StorageSubItem.displayName = 'StorageSubItem' - -export default StorageSubItem diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/index.js b/src/fireedge/src/client/components/Tabs/Vm/Storage/index.js index 22eb535e18..f12adc9093 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Storage/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/Storage/index.js @@ -13,29 +13,53 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext, useMemo } from 'react' +import { ReactElement, useMemo } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useVmApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' - -import StorageList from 'client/components/Tabs/Vm/Storage/List' -import ButtonToTriggerForm from 'client/components/Forms/ButtonToTriggerForm' -import { ImageSteps, VolatileSteps } from 'client/components/Forms/Vm' +import { useGetVmQuery } from 'client/features/OneApi/vm' +import { + AttachAction, + SaveAsAction, + ResizeAction, + DetachAction, + SnapshotCreateAction, + SnapshotRevertAction, + SnapshotRenameAction, + SnapshotDeleteAction, +} from 'client/components/Tabs/Vm/Storage/Actions' +import DiskCard from 'client/components/Cards/DiskCard' import { getDisks, getHypervisor, isAvailableAction, } from 'client/models/VirtualMachine' -import { getActionsAvailable, jsonToXml } from 'client/models/Helper' -import { T, VM_ACTIONS } from 'client/constants' +import { getActionsAvailable } from 'client/models/Helper' +import { VM_ACTIONS } from 'client/constants' -const VmStorageTab = ({ tabProps: { actions } = {} }) => { - const { attachDisk } = useVmApi() +const { + ATTACH_DISK, + DETACH_DISK, + DISK_SAVEAS, + RESIZE_DISK, + SNAPSHOT_DISK_CREATE, + SNAPSHOT_DISK_RENAME, + SNAPSHOT_DISK_REVERT, + SNAPSHOT_DISK_DELETE, +} = VM_ACTIONS - const { data: vm = {} } = useContext(TabContext) +/** + * Renders the list of disks from a VM. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string[]} props.tabProps.actions - Actions tab + * @param {string} props.id - Virtual Machine id + * @returns {ReactElement} Storage tab + */ +const VmStorageTab = ({ tabProps: { actions } = {}, id }) => { + const { data: vm = {} } = useGetVmQuery(id) const [disks, hypervisor, actionsAvailable] = useMemo(() => { const hyperV = getHypervisor(vm) @@ -47,48 +71,49 @@ const VmStorageTab = ({ tabProps: { actions } = {} }) => { return [getDisks(vm), hyperV, actionsByState] }, [vm]) - const handleAttachDisk = async (formData) => { - const template = jsonToXml({ DISK: formData }) - - await attachDisk(vm.ID, template) - } + const filterByAvailable = (action, button) => + actionsAvailable.includes(action) && button return ( <> - {actionsAvailable?.includes?.(VM_ACTIONS.ATTACH_DISK) && ( - ImageSteps({ hypervisor }), - onSubmit: handleAttachDisk, - }, - { - cy: 'attach-volatile', - name: T.Volatile, - dialogProps: { title: T.AttachVolatile }, - form: () => VolatileSteps({ hypervisor }), - onSubmit: handleAttachDisk, - }, - ]} - /> + {actionsAvailable?.includes?.(ATTACH_DISK) && ( + )} - + + {disks.map((disk) => { + const isImage = disk.IMAGE_ID !== undefined + + return ( + + ) + })} + ) } VmStorageTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } VmStorageTab.displayName = 'VmStorageTab' diff --git a/src/fireedge/src/client/components/Tabs/Vm/index.js b/src/fireedge/src/client/components/Tabs/Vm/index.js index c89dc0a95a..1b46e3736c 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/index.js +++ b/src/fireedge/src/client/components/Tabs/Vm/index.js @@ -13,23 +13,19 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useEffect, useState } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { LinearProgress } from '@mui/material' -import { useFetch, useSocket } from 'client/hooks' import { useAuth } from 'client/features/Auth' -import { useVmApi } from 'client/features/One' +import { useGetVmQuery } from 'client/features/OneApi/vm' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' import Tabs from 'client/components/Tabs' -import { camelCase } from 'client/utils' - -import TabProvider from 'client/components/Tabs/TabProvider' import Capacity from 'client/components/Tabs/Vm/Capacity' import Configuration from 'client/components/Tabs/Vm/Configuration' import Info from 'client/components/Tabs/Vm/Info' -import Log from 'client/components/Tabs/Vm/Log' import Network from 'client/components/Tabs/Vm/Network' import History from 'client/components/Tabs/Vm/History' import SchedActions from 'client/components/Tabs/Vm/SchedActions' @@ -41,7 +37,6 @@ const getTabComponent = (tabName) => capacity: Capacity, configuration: Configuration, info: Info, - log: Log, network: Network, history: History, schedActions: SchedActions, @@ -50,60 +45,24 @@ const getTabComponent = (tabName) => }[tabName]) const VmTabs = memo(({ id }) => { - const { getHooksSocket } = useSocket() - const { getVm } = useVmApi() - - const { data, fetchRequest, loading, error } = useFetch( - getVm, - getHooksSocket({ resource: 'vm', id }) - ) - - const handleRefetch = () => fetchRequest(id, { reload: true }) - - const [tabsAvailable, setTabs] = useState(() => []) const { view, getResourceView } = useAuth() + const { isLoading } = useGetVmQuery(id) - useEffect(() => { - fetchRequest(id) - }, [id]) + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.VM + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} - useEffect(() => { - const infoTabs = getResourceView('VM')?.['info-tabs'] ?? {} - - setTabs(() => - Object.entries(infoTabs) - ?.filter(([_, { enabled } = {}]) => !!enabled) - ?.map(([tabName, tabProps]) => { - const camelName = camelCase(tabName) - const TabContent = getTabComponent(camelName) - - return ( - TabContent && { - name: camelName, - id: tabName, - renderContent: (props) => TabContent({ ...props, tabProps }), - } - ) - }) - ?.filter(Boolean) - ) + return getAvailableInfoTabs(infoTabs, getTabComponent, id) }, [view]) - if ((!data && !error) || loading) { - return - } - - return ( - - - + return isLoading ? ( + + ) : ( + ) }) -VmTabs.propTypes = { - id: PropTypes.string.isRequired, -} - +VmTabs.propTypes = { id: PropTypes.string.isRequired } VmTabs.displayName = 'VmTabs' export default VmTabs diff --git a/src/fireedge/src/client/components/Tabs/VmTemplate/Info/index.js b/src/fireedge/src/client/components/Tabs/VmTemplate/Info/index.js index 29c78e0359..850488a2e7 100644 --- a/src/fireedge/src/client/components/Tabs/VmTemplate/Info/index.js +++ b/src/fireedge/src/client/components/Tabs/VmTemplate/Info/index.js @@ -13,57 +13,59 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext } from 'react' +import { ReactElement } from 'react' import PropTypes from 'prop-types' +import { Stack } from '@mui/material' -import { useVmTemplateApi } from 'client/features/One' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { + useGetTemplateQuery, + useChangeTemplatePermissionsMutation, + useChangeTemplateOwnershipMutation, +} from 'client/features/OneApi/vmTemplate' import { Permissions, Ownership } from 'client/components/Tabs/Common' import Information from 'client/components/Tabs/VmTemplate/Info/information' import * as Helper from 'client/models/Helper' -const VmTemplateInfoTab = ({ tabProps = {} }) => { +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Template id + * @returns {ReactElement} Information tab + */ +const VmTemplateInfoTab = ({ tabProps = {}, id }) => { const { information_panel: informationPanel, permissions_panel: permissionsPanel, ownership_panel: ownershipPanel, } = tabProps - const { rename, changeOwnership, changePermissions } = useVmTemplateApi() - const { handleRefetch, data: template = {} } = useContext(TabContext) + const [changeOwnership] = useChangeTemplatePermissionsMutation() + const [changePermissions] = useChangeTemplateOwnershipMutation() + const { data: template = {} } = useGetTemplateQuery({ id }) const { ID, UNAME, UID, GNAME, GID, PERMISSIONS } = template const handleChangeOwnership = async (newOwnership) => { - const response = await changeOwnership(ID, newOwnership) - String(response) === String(ID) && (await handleRefetch?.()) + await changeOwnership({ id: ID, ...newOwnership }) } const handleChangePermission = async (newPermission) => { - const response = await changePermissions(ID, newPermission) - String(response) === String(ID) && (await handleRefetch?.()) - } - - const handleRename = async (_, newName) => { - const response = await rename(ID, newName) - String(response) === String(ID) && (await handleRefetch?.()) + await changePermissions({ id: ID, ...newPermission }) } const getActions = (actions) => Helper.getActionsAvailable(actions) return ( -
{informationPanel?.enabled && ( )} @@ -92,12 +94,13 @@ const VmTemplateInfoTab = ({ tabProps = {} }) => { handleEdit={handleChangeOwnership} /> )} -
+
) } VmTemplateInfoTab.propTypes = { tabProps: PropTypes.object, + id: PropTypes.string, } VmTemplateInfoTab.displayName = 'VmTemplateInfoTab' diff --git a/src/fireedge/src/client/components/Tabs/VmTemplate/Info/information.js b/src/fireedge/src/client/components/Tabs/VmTemplate/Info/information.js index c4ee06e863..fd1df99a3b 100644 --- a/src/fireedge/src/client/components/Tabs/VmTemplate/Info/information.js +++ b/src/fireedge/src/client/components/Tabs/VmTemplate/Info/information.js @@ -13,17 +13,32 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' import { List } from 'client/components/Tabs/Common' +import { useRenameTemplateMutation } from 'client/features/OneApi/vmTemplate' -import * as Helper from 'client/models/Helper' -import { T, VM_TEMPLATE_ACTIONS } from 'client/constants' +import { timeToString, levelLockToString } from 'client/models/Helper' +import { T, VM_TEMPLATE_ACTIONS, VmTemplate } from 'client/constants' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {VmTemplate} props.template - Template + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ template = {}, actions }) => { + const [renameTemplate] = useRenameTemplateMutation() -const InformationPanel = ({ template = {}, handleRename, actions }) => { const { ID, NAME, REGTIME, LOCK } = template + const handleRename = async (_, newName) => { + await renameTemplate({ id: ID, name: newName }) + } + const info = [ { name: T.ID, value: ID, dataCy: 'id' }, { @@ -35,24 +50,29 @@ const InformationPanel = ({ template = {}, handleRename, actions }) => { }, { name: T.StartTime, - value: Helper.timeToString(REGTIME), + value: timeToString(REGTIME), dataCy: 'starttime', }, { name: T.Locked, - value: Helper.levelLockToString(LOCK?.LOCKED), + value: levelLockToString(LOCK?.LOCKED), dataCy: 'locked', }, ] - return + return ( + + ) } InformationPanel.displayName = 'InformationPanel' InformationPanel.propTypes = { actions: PropTypes.arrayOf(PropTypes.string), - handleRename: PropTypes.func, template: PropTypes.object, } diff --git a/src/fireedge/src/client/components/Tabs/VmTemplate/Template.js b/src/fireedge/src/client/components/Tabs/VmTemplate/Template.js index 036da3f34a..d19e2d4817 100644 --- a/src/fireedge/src/client/components/Tabs/VmTemplate/Template.js +++ b/src/fireedge/src/client/components/Tabs/VmTemplate/Template.js @@ -13,14 +13,21 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useContext } from 'react' +import { ReactElement } from 'react' +import PropTypes from 'prop-types' import { Accordion, AccordionDetails } from '@mui/material' -import { TabContext } from 'client/components/Tabs/TabProvider' +import { useGetTemplateQuery } from 'client/features/OneApi/vmTemplate' -const TemplateTab = () => { - const { data: template = {} } = useContext(TabContext) +/** + * Renders template tab. + * + * @param {object} props - Props + * @param {string} props.id - Template id + * @returns {ReactElement} Template tab + */ +const TemplateTab = ({ id }) => { + const { data: template = {} } = useGetTemplateQuery({ id }) const { TEMPLATE } = template return ( @@ -36,6 +43,11 @@ const TemplateTab = () => { ) } +TemplateTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + TemplateTab.displayName = 'TemplateTab' export default TemplateTab diff --git a/src/fireedge/src/client/components/Tabs/VmTemplate/index.js b/src/fireedge/src/client/components/Tabs/VmTemplate/index.js index 2268493237..cbca687d2f 100644 --- a/src/fireedge/src/client/components/Tabs/VmTemplate/index.js +++ b/src/fireedge/src/client/components/Tabs/VmTemplate/index.js @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { memo, useEffect, useState } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { LinearProgress } from '@mui/material' -import { useFetch } from 'client/hooks' import { useAuth } from 'client/features/Auth' -import { useVmTemplateApi } from 'client/features/One' +import { useGetTemplateQuery } from 'client/features/OneApi/vmTemplate' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' import Tabs from 'client/components/Tabs' -import { camelCase } from 'client/utils' - -import TabProvider from 'client/components/Tabs/TabProvider' import Info from 'client/components/Tabs/VmTemplate/Info' import Template from 'client/components/Tabs/VmTemplate/Template' @@ -36,55 +33,24 @@ const getTabComponent = (tabName) => }[tabName]) const VmTemplateTabs = memo(({ id }) => { - const { getVmTemplate } = useVmTemplateApi() - const { data, fetchRequest, loading, error } = useFetch(getVmTemplate) - - const handleRefetch = () => fetchRequest(id, { reload: true }) - - const [tabsAvailable, setTabs] = useState(() => []) const { view, getResourceView } = useAuth() + const { isLoading } = useGetTemplateQuery({ id }) - useEffect(() => { - fetchRequest(id) - }, [id]) + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.VM_TEMPLATE + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} - useEffect(() => { - const infoTabs = getResourceView('VM-TEMPLATE')?.['info-tabs'] ?? {} - - setTabs(() => - Object.entries(infoTabs) - ?.filter(([_, { enabled } = {}]) => !!enabled) - ?.map(([tabName, tabProps]) => { - const camelName = camelCase(tabName) - const TabContent = getTabComponent(camelName) - - return ( - TabContent && { - name: camelName, - id: tabName, - renderContent: (props) => TabContent({ ...props, tabProps }), - } - ) - }) - ?.filter(Boolean) - ) + return getAvailableInfoTabs(infoTabs, getTabComponent, id) }, [view]) - if ((!data && !error) || loading) { - return - } - - return ( - - - + return isLoading ? ( + + ) : ( + ) }) -VmTemplateTabs.propTypes = { - id: PropTypes.string.isRequired, -} - +VmTemplateTabs.propTypes = { id: PropTypes.string.isRequired } VmTemplateTabs.displayName = 'VmTemplateTabs' export default VmTemplateTabs diff --git a/src/fireedge/src/client/components/Tabs/Zone/Info/index.js b/src/fireedge/src/client/components/Tabs/Zone/Info/index.js new file mode 100644 index 0000000000..fc9267a520 --- /dev/null +++ b/src/fireedge/src/client/components/Tabs/Zone/Info/index.js @@ -0,0 +1,101 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' +import { Stack } from '@mui/material' + +import { + useGetZoneQuery, + useUpdateZoneMutation, +} from 'client/features/OneApi/zone' +import { AttributePanel } from 'client/components/Tabs/Common' +import Information from 'client/components/Tabs/Zone/Info/information' + +import { Tr } from 'client/components/HOC' +import { T } from 'client/constants' +import { jsonToXml, getActionsAvailable } from 'client/models/Helper' +import { cloneObject, set } from 'client/utils' + +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {object} props.tabProps - Tab information + * @param {string} props.id - Zone id + * @returns {ReactElement} Information tab + */ +const ZoneInfoTab = ({ tabProps = {}, id }) => { + const { + information_panel: informationPanel, + attributes_panel: attributesPanel, + } = tabProps + + const [update] = useUpdateZoneMutation() + const { data: zone } = useGetZoneQuery(id) + const { TEMPLATE } = zone + + const handleAttributeInXml = async (path, newValue) => { + const newTemplate = cloneObject(TEMPLATE) + set(newTemplate, path, newValue) + + const xml = jsonToXml(newTemplate) + await update({ id, template: xml, replace: 0 }) + } + + const getActions = useCallback( + (actions) => getActionsAvailable(actions), + [getActionsAvailable] + ) + + const ATTRIBUTE_FUNCTION = { + handleAdd: handleAttributeInXml, + handleEdit: handleAttributeInXml, + handleDelete: handleAttributeInXml, + } + + return ( + + {informationPanel?.enabled && ( + + )} + {attributesPanel?.enabled && ( + + )} + + ) +} + +ZoneInfoTab.propTypes = { + tabProps: PropTypes.object, + id: PropTypes.string, +} + +ZoneInfoTab.displayName = 'ZoneInfoTab' + +export default ZoneInfoTab diff --git a/src/fireedge/src/client/components/Tabs/Vm/Storage/List.js b/src/fireedge/src/client/components/Tabs/Zone/Info/information.js similarity index 53% rename from src/fireedge/src/client/components/Tabs/Vm/Storage/List.js rename to src/fireedge/src/client/components/Tabs/Zone/Info/information.js index 9034532b07..cd19bf4918 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Storage/List.js +++ b/src/fireedge/src/client/components/Tabs/Zone/Info/information.js @@ -13,24 +13,52 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import PropTypes from 'prop-types' -import StorageItem from 'client/components/Tabs/Vm/Storage/Item' +import { useRenameZoneMutation } from 'client/features/OneApi/zone' +import { List } from 'client/components/Tabs/Common' +import { T, Zone, ZONE_ACTIONS } from 'client/constants' -const StorageList = ({ disks, actions }) => ( -
- {disks.map((disk, idx) => ( - - ))} -
-) +/** + * Renders mainly information tab. + * + * @param {object} props - Props + * @param {Zone} props.zone - Zone resource + * @param {string[]} props.actions - Available actions to information tab + * @returns {ReactElement} Information tab + */ +const InformationPanel = ({ zone = {}, actions }) => { + const [rename] = useRenameZoneMutation() + const { ID, NAME } = zone -StorageList.propTypes = { - disks: PropTypes.array, + const handleRename = async (_, newName) => { + await rename({ id: ID, name: newName }) + } + + const info = [ + { name: T.ID, value: ID, dataCy: 'id' }, + { + name: T.Name, + value: NAME, + dataCy: 'name', + canEdit: actions?.includes?.(ZONE_ACTIONS.RENAME), + handleEdit: handleRename, + }, + ] + + return ( + <> + + + ) +} + +InformationPanel.propTypes = { + zone: PropTypes.object, actions: PropTypes.arrayOf(PropTypes.string), } -StorageList.displayName = 'StorageList' +InformationPanel.displayName = 'InformationPanel' -export default StorageList +export default InformationPanel diff --git a/src/fireedge/src/client/components/Tabs/TabProvider.js b/src/fireedge/src/client/components/Tabs/Zone/index.js similarity index 53% rename from src/fireedge/src/client/components/Tabs/TabProvider.js rename to src/fireedge/src/client/components/Tabs/Zone/index.js index d8ebef8201..2a9d1d8197 100644 --- a/src/fireedge/src/client/components/Tabs/TabProvider.js +++ b/src/fireedge/src/client/components/Tabs/Zone/index.js @@ -13,33 +13,42 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, createContext, useState } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' +import { LinearProgress } from '@mui/material' -export const TabContext = createContext(null) +import { useAuth } from 'client/features/Auth' +import { useGetZoneQuery } from 'client/features/OneApi/zone' +import { getAvailableInfoTabs } from 'client/models/Helper' +import { RESOURCE_NAMES } from 'client/constants' -const TabProvider = ({ initialState = {}, children }) => { - const [information, setTabInformation] = useState(() => initialState) - const { data } = initialState +import Tabs from 'client/components/Tabs' +import Info from 'client/components/Tabs/Zone/Info' - useEffect(() => { - data && setTabInformation((prev) => ({ ...prev, data })) - }, [data]) +const getTabComponent = (tabName) => + ({ + info: Info, + }[tabName]) - return ( - - {children} - +const ZoneTabs = memo(({ id }) => { + const { view, getResourceView } = useAuth() + const { isLoading } = useGetZoneQuery(id) + + const tabsAvailable = useMemo(() => { + const resource = RESOURCE_NAMES.ZONE + const infoTabs = getResourceView(resource)?.['info-tabs'] ?? {} + + return getAvailableInfoTabs(infoTabs, getTabComponent, id) + }, [view]) + + return isLoading ? ( + + ) : ( + ) -} +}) -TabProvider.propTypes = { - initialState: PropTypes.object, - children: PropTypes.oneOfType([ - PropTypes.node, - PropTypes.arrayOf(PropTypes.node), - ]), -} +ZoneTabs.propTypes = { id: PropTypes.string.isRequired } +ZoneTabs.displayName = 'ZoneTabs' -export default TabProvider +export default ZoneTabs diff --git a/src/fireedge/src/client/components/Tabs/index.js b/src/fireedge/src/client/components/Tabs/index.js index 907ab30988..9f29f8f630 100644 --- a/src/fireedge/src/client/components/Tabs/index.js +++ b/src/fireedge/src/client/components/Tabs/index.js @@ -36,7 +36,9 @@ const Content = ({ name, renderContent: RenderContent, hidden }) => ( sx={{ p: (theme) => theme.spacing(2, 1), height: '100%', - display: hidden ? 'none' : 'block', + display: hidden ? 'none' : 'flex', + flexDirection: 'column', + overflow: 'auto', }} > {typeof RenderContent === 'function' ? : RenderContent} diff --git a/src/fireedge/src/client/components/Widgets/TotalProviders/index.js b/src/fireedge/src/client/components/Widgets/TotalProviders/index.js index a2f4a4b26e..fbc16719f5 100644 --- a/src/fireedge/src/client/components/Widgets/TotalProviders/index.js +++ b/src/fireedge/src/client/components/Widgets/TotalProviders/index.js @@ -13,14 +13,15 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo } from 'react' +import { useMemo, ReactElement } from 'react' import { PieChart } from 'react-minimal-pie-chart' -import { Skeleton, Typography, Paper } from '@mui/material' +import { Typography, Paper, CircularProgress } from '@mui/material' -import { useAuth } from 'client/features/Auth' -import { useProvider } from 'client/features/One' +import { + useGetProviderConfigQuery, + useGetProvidersQuery, +} from 'client/features/OneApi/provider' import { TypographyWithPoint } from 'client/components/Typography' import NumberEasing from 'client/components/NumberEasing' import { groupBy } from 'client/utils' @@ -28,35 +29,27 @@ import { T } from 'client/constants' import useStyles from 'client/components/Widgets/TotalProviders/styles' -const TotalProviders = ({ isLoading }) => { +/** + * Renders a widget to display the all providers grouped by type. + * + * @returns {ReactElement} Total providers by type + */ +const TotalProviders = () => { const classes = useStyles() - const { providerConfig } = useAuth() - const providers = useProvider() + const { data: config } = useGetProviderConfigQuery() + const { data: providers = [], isLoading } = useGetProvidersQuery() const totalProviders = providers?.length const chartData = useMemo(() => { const groups = groupBy(providers, 'TEMPLATE.PLAIN.provider') - return Object.entries(providerConfig).map(([id, { name, color }]) => ({ + return Object.entries(config).map(([id, { name, color }]) => ({ color, title: name, value: groups[id]?.length ?? 0, })) }, [totalProviders]) - const title = useMemo( - () => ( -
- - - {T.Providers} - - {T.InTotal} -
- ), - [classes, totalProviders] - ) - const legend = useMemo( () => (
@@ -87,23 +80,27 @@ const TotalProviders = ({ isLoading }) => { [classes, chartData] ) - return useMemo( - () => - !totalProviders && isLoading ? ( - - ) : ( - - {title} -
- {chart} - {legend} -
-
- ), - [classes, chart, totalProviders, isLoading] + return ( + +
+ + {isLoading ? ( + + ) : ( + + )} + {T.Providers} + + {T.InTotal} +
+
+ {chart} + {legend} +
+
) } diff --git a/src/fireedge/src/client/components/Widgets/TotalProvisionInfrastructures.js b/src/fireedge/src/client/components/Widgets/TotalProvisionInfrastructures.js deleted file mode 100644 index 648f87c2e8..0000000000 --- a/src/fireedge/src/client/components/Widgets/TotalProvisionInfrastructures.js +++ /dev/null @@ -1,138 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useMemo } from 'react' - -import { - Server as ClusterIcon, - HardDrive as HostIcon, - Folder as DatastoreIcon, - NetworkAlt as NetworkIcon, -} from 'iconoir-react' -import { Skeleton, Grid } from '@mui/material' - -import { useProvision } from 'client/features/One' -import NumberEasing from 'client/components/NumberEasing' -import { WavesCard } from 'client/components/Cards' -import { get } from 'client/utils' -import { T } from 'client/constants' - -const TOTAL_WIDGETS = 4 -const breakpoints = { xs: 12, sm: 6, md: 3 } - -const TotalProvisionInfrastructures = ({ isLoading }) => { - const provisions = useProvision() - - const provisionsByProvider = useMemo( - () => - provisions?.map((provision) => ({ - provider: get(provision, 'TEMPLATE.BODY.provider'), - clusters: get( - provision, - 'TEMPLATE.BODY.provision.infrastructure.clusters', - [] - ).length, - hosts: get( - provision, - 'TEMPLATE.BODY.provision.infrastructure.hosts', - [] - ).length, - networks: get( - provision, - 'TEMPLATE.BODY.provision.infrastructure.networks', - [] - ).length, - datastores: get( - provision, - 'TEMPLATE.BODY.provision.infrastructure.datastores', - [] - ).length, - })), - [provisions] - ) - - const totals = useMemo( - () => - provisionsByProvider?.reduce( - (total, { clusters, hosts, datastores, networks }) => ({ - clusters: clusters + total.clusters, - hosts: hosts + total.hosts, - datastores: datastores + total.datastores, - networks: networks + total.networks, - }), - { clusters: 0, hosts: 0, datastores: 0, networks: 0 } - ), - [provisionsByProvider] - ) - - return useMemo( - () => ( - - {!totals?.clusters?.length && isLoading ? ( - Array.from(Array(TOTAL_WIDGETS)).map((_, index) => ( - - - - )) - ) : ( - <> - - } - bgColor="#fa7892" - icon={ClusterIcon} - /> - - - } - bgColor="#b25aff" - icon={HostIcon} - /> - - - } - bgColor="#1fbbc6" - icon={DatastoreIcon} - /> - - - } - bgColor="#f09d42" - icon={NetworkIcon} - /> - - - )} - - ), - [totals?.clusters, isLoading] - ) -} - -TotalProvisionInfrastructures.displayName = 'TotalProvisionInfrastructures' - -export default TotalProvisionInfrastructures diff --git a/src/fireedge/src/client/components/Widgets/TotalProvisionsByState/index.js b/src/fireedge/src/client/components/Widgets/TotalProvisionsByState/index.js index 2d2b4a1767..90fee95814 100644 --- a/src/fireedge/src/client/components/Widgets/TotalProvisionsByState/index.js +++ b/src/fireedge/src/client/components/Widgets/TotalProvisionsByState/index.js @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useMemo } from 'react' +import { useMemo, ReactElement } from 'react' -import { Skeleton, Paper, Typography } from '@mui/material' +import { Paper, Typography, CircularProgress } from '@mui/material' -import { useProvision } from 'client/features/One' +import { useGetProvisionsQuery } from 'client/features/OneApi/provision' import { SingleBar } from 'client/components/Charts' import NumberEasing from 'client/components/NumberEasing' import { groupBy } from 'client/utils' @@ -26,9 +25,14 @@ import { T, PROVISIONS_STATES } from 'client/constants' import useStyles from 'client/components/Widgets/TotalProvisionsByState/styles' -const TotalProvisionsByState = ({ isLoading }) => { +/** + * Renders a widget to display the provisions grouped by state. + * + * @returns {ReactElement} Total provisions by state + */ +const TotalProvisionsByState = () => { const classes = useStyles() - const provisions = useProvision() + const { data: provisions = [], isLoading } = useGetProvisionsQuery() const totalProvisions = provisions?.length const chartData = useMemo(() => { @@ -39,39 +43,30 @@ const TotalProvisionsByState = ({ isLoading }) => { ) }, [totalProvisions]) - const title = useMemo( - () => ( + return ( +
- + {isLoading ? ( + + ) : ( + + )} {T.Provisions} {T.InTotal}
- ), - [classes, totalProvisions] - ) - - return useMemo( - () => - !totalProvisions && isLoading ? ( - - ) : ( - - {title} -
- -
-
- ), - [classes, chartData, totalProvisions, isLoading] +
+ +
+
) } diff --git a/src/fireedge/src/client/components/Widgets/TotalSunstoneResources.js b/src/fireedge/src/client/components/Widgets/TotalSunstoneResources.js deleted file mode 100644 index 23e15c1181..0000000000 --- a/src/fireedge/src/client/components/Widgets/TotalSunstoneResources.js +++ /dev/null @@ -1,98 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useMemo } from 'react' - -import { - User as UserIcon, - Group as GroupIcon, - Archive as ImageIcon, - NetworkAlt as NetworkIcon, -} from 'iconoir-react' -import { Skeleton, Grid } from '@mui/material' - -import { useUser, useGroup, useImage, useVNetwork } from 'client/features/One' -import NumberEasing from 'client/components/NumberEasing' -import { WavesCard } from 'client/components/Cards' -import { T } from 'client/constants' - -const TOTAL_WIDGETS = 4 -const breakpoints = { xs: 12, sm: 6, md: 3 } - -const TotalProvisionInfrastructures = ({ isLoading }) => { - const users = useUser() - const groups = useGroup() - const images = useImage() - const vNetworks = useVNetwork() - - return useMemo( - () => ( - - {!users?.length && isLoading ? ( - Array.from(Array(TOTAL_WIDGETS)).map((_, index) => ( - - - - )) - ) : ( - <> - - } - bgColor="#fa7892" - icon={UserIcon} - /> - - - } - bgColor="#b25aff" - icon={GroupIcon} - /> - - - } - bgColor="#1fbbc6" - icon={ImageIcon} - /> - - - } - bgColor="#f09d42" - icon={NetworkIcon} - /> - - - )} - - ), - [users?.length, isLoading] - ) -} - -TotalProvisionInfrastructures.displayName = 'TotalProvisionInfrastructures' - -export default TotalProvisionInfrastructures diff --git a/src/fireedge/src/client/components/Widgets/index.js b/src/fireedge/src/client/components/Widgets/index.js index 50f5af8d83..50b3d3bb67 100644 --- a/src/fireedge/src/client/components/Widgets/index.js +++ b/src/fireedge/src/client/components/Widgets/index.js @@ -15,12 +15,5 @@ * ------------------------------------------------------------------------- */ import TotalProviders from 'client/components/Widgets/TotalProviders' import TotalProvisionsByState from 'client/components/Widgets/TotalProvisionsByState' -import TotalProvisionInfrastructures from 'client/components/Widgets/TotalProvisionInfrastructures' -import TotalSunstoneResources from 'client/components/Widgets/TotalSunstoneResources' -export { - TotalProviders, - TotalProvisionInfrastructures, - TotalProvisionsByState, - TotalSunstoneResources, -} +export { TotalProviders, TotalProvisionsByState } diff --git a/src/fireedge/src/client/constants/cluster.js b/src/fireedge/src/client/constants/cluster.js index 555f6f9873..5f2c25ff6c 100644 --- a/src/fireedge/src/client/constants/cluster.js +++ b/src/fireedge/src/client/constants/cluster.js @@ -15,6 +15,18 @@ * ------------------------------------------------------------------------- */ import * as ACTIONS from 'client/constants/actions' +/** + * @typedef Cluster + * @property {string} ID - Id + * @property {string} NAME - Name + * @property {{ ID: string|string[] }} HOSTS - Hosts + * @property {{ ID: string|string[] }} DATASTORES - Datastores + * @property {{ ID: string|string[] }} VNETS - Virtual networks + * @property {object} TEMPLATE - Template + * @property {string} [TEMPLATE.RESERVED_MEM] - Reserved memory + * @property {string} [TEMPLATE.RESERVED_CPU] - Reserved CPU + */ + /** @enum {string} Cluster actions */ export const CLUSTER_ACTIONS = { CREATE_DIALOG: 'create_dialog', diff --git a/src/fireedge/src/client/constants/common.js b/src/fireedge/src/client/constants/common.js new file mode 100644 index 0000000000..fa559f4d54 --- /dev/null +++ b/src/fireedge/src/client/constants/common.js @@ -0,0 +1,58 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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. * + * ------------------------------------------------------------------------- */ + +/** + * @typedef {'1'|'2'|'3'|'4'} LockLevel + * - `USE` (1): locks Admin, Manage and Use actions. + * - `MANAGE` (2): locks Manage and Use actions. + * - `ADMIN` (3): locks only Admin actions. + * - `ALL` (4): locks all actions. + */ + +/** + * @typedef {object} LockInfo + * @property {'0'|'1'} LOCKED - If `1` is locked + * @property {string|number} OWNER - Owner + * @property {string|number} TIME - Time + * @property {string|number} REQ_ID - Request id + */ + +/** + * @typedef {number|'-4'|'-3'|'-2'|'-1'} FilterFlag + * - `-4`: Resources belonging to the user’s primary group + * - `-3`: Resources belonging to the user + * - `-2`: All resources + * - `-1`: Resources belonging to the user and any of his groups + * - `>= 0`: UID User’s Resources + */ + +/** @typedef {'0'|'1'} Permission */ + +/** + * @typedef {object} Permissions + * @property {Permission} OWNER_U - Owner use + * @property {Permission} OWNER_M - Owner manage + * @property {Permission} OWNER_A - Owner administrator + * @property {Permission} GROUP_U - Group use + * @property {Permission} GROUP_M - Group manage + * @property {Permission} GROUP_A - Group administrator + * @property {Permission} OTHER_U - Other use + * @property {Permission} OTHER_M - Other manage + * @property {Permission} OTHER_A - Other administrator + */ + +export const YES_VALUE = 'YES' +export const NO_VALUE = 'NO' diff --git a/src/fireedge/src/client/constants/datastore.js b/src/fireedge/src/client/constants/datastore.js index c83d716aa0..56aebb7418 100644 --- a/src/fireedge/src/client/constants/datastore.js +++ b/src/fireedge/src/client/constants/datastore.js @@ -13,8 +13,45 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +import * as ACTIONS from 'client/constants/actions' import * as STATES from 'client/constants/states' import COLOR from 'client/constants/color' +// eslint-disable-next-line no-unused-vars +import { DISK_TYPES_STR } from 'client/constants/image' +// eslint-disable-next-line no-unused-vars +import { Permissions } from 'client/constants/common' + +/** + * @typedef Datastore + * @property {string|number} ID - Id + * @property {string} NAME - Name + * @property {string|number} UID - User id + * @property {string} UNAME - User name + * @property {string|number} GID - Group id + * @property {string} GNAME - Group name + * @property {0|1} STATE - Possible STATE values are 0 (READY) and 1 (DISABLE) + * @property {Permissions} [PERMISSIONS] - Permissions + * @property {string} DS_MAD - Datastore driver name + * @property {string} TM_MAD - Transfer driver name + * @property {string} BASE_PATH - Datastore directory + * @property {DATASTORE_TYPES} TYPE - Type + * @property {DISK_TYPES_STR} DISK_TYPE - Disk type + * @property {{ ID: string[] }} CLUSTERS - Clusters + * @property {{ ID: string[] }} IMAGES - Images + * @property {string|number} TOTAL_MB - Total capacity + * @property {string|number} FREE_MB - Free capacity + * @property {string|number} USED_MB - Used capacity + * @property {object} TEMPLATE - Template + * @property {string} [TEMPLATE.RESTRICTED_DIRS] - Paths that cannot be used to register images. A space separated list of paths. + * @property {string} [TEMPLATE.SAFE_DIRS] - If you need to allow a directory listed under RESTRICTED_DIRS. A space separated list of paths. + * @property {string} [TEMPLATE.ALLOW_ORPHANS] - Safe directories + * @property {string} [TEMPLATE.VCENTER_DC_NAME] - vCenter information + * @property {string} [TEMPLATE.VCENTER_DC_REF] - vCenter information + * @property {string} [TEMPLATE.VCENTER_DS_NAME] - vCenter information + * @property {string} [TEMPLATE.VCENTER_DS_REF] - vCenter information + * @property {string} [TEMPLATE.VCENTER_HOST] - vCenter information + * @property {string} [TEMPLATE.VCENTER_INSTANCE_ID] - vCenter information + */ /** @type {string[]} Datastore type information */ export const DATASTORE_TYPES = ['IMAGE', 'SYSTEM', 'FILE'] @@ -32,3 +69,15 @@ export const DATASTORE_STATES = [ color: COLOR.error.dark, }, ] + +/** @enum {string} Datastore actions */ +export const DATASTORE_ACTIONS = { + CREATE_DIALOG: 'create_dialog', + DELETE: 'delete', + + // INFORMATION + RENAME: ACTIONS.RENAME, + CHANGE_MODE: ACTIONS.CHANGE_MODE, + CHANGE_OWNER: ACTIONS.CHANGE_OWNER, + CHANGE_GROUP: ACTIONS.CHANGE_GROUP, +} diff --git a/src/fireedge/src/client/constants/group.js b/src/fireedge/src/client/constants/group.js new file mode 100644 index 0000000000..3e33bdeb41 --- /dev/null +++ b/src/fireedge/src/client/constants/group.js @@ -0,0 +1,46 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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-next-line prettier/prettier, no-unused-vars +import { VmQuota, NetworkQuota, DatastoreQuota, ImageQuota } from 'client/constants/quota' +import * as ACTIONS from 'client/constants/actions' + +/** + * @typedef Group + * @property {string|number} ID - Id + * @property {string} NAME - Name + * @property {{ ID: string[] }} [USERS] - List of user ids + * @property {{ ID: string[] }} [ADMINS] - List of admin ids + * @property {string|number} TEMPLATE - Template + * @property {{ DATASTORE: DatastoreQuota|DatastoreQuota[] }} [DATASTORE_QUOTA] - Datastore quotas + * @property {{ NETWORK: NetworkQuota|NetworkQuota[] }} [NETWORK_QUOTA] - Network quotas + * @property {{ VM: VmQuota }} [VM_QUOTA] - VM quotas + * @property {{ IMAGE: ImageQuota|ImageQuota[] }} [IMAGE_QUOTA] - Image quotas + * @property {{ + * DATASTORE: DatastoreQuota|DatastoreQuota[], + * NETWORK: NetworkQuota|NetworkQuota[], + * VM: VmQuota, + * IMAGE: ImageQuota|ImageQuota[] + * }} [DEFAULT_GROUP_QUOTAS] - Default quotas + */ + +export const GROUP_ACTIONS = { + REFRESH: ACTIONS.REFRESH, + CREATE_DIALOG: 'create_dialog', + UPDATE_DIALOG: 'update_dialog', + QUOTAS_DIALOG: 'quotas_dialog', + DELETE: 'delete', + EDIT_ADMINS: 'edit_admins', +} diff --git a/src/fireedge/src/client/constants/host.js b/src/fireedge/src/client/constants/host.js index f1a3b702c8..d52e0d2705 100644 --- a/src/fireedge/src/client/constants/host.js +++ b/src/fireedge/src/client/constants/host.js @@ -19,18 +19,108 @@ import COLOR from 'client/constants/color' /** * @typedef {object} PciDevice - PCI device - * @property {string} DOMAIN - PCI address domain - * @property {string} BUS - PCI address bus - * @property {string} SLOT - PCI address slot - * @property {string} FUNCTION - PCI address function - * @property {string} ADDRESS - PCI address, bus, slot and function - * @property {string} DEVICE - Id of PCI device + * @property {string} ADDRESS - Address, bus, slot and function + * @property {string} BUS - Address bus * @property {string} CLASS - Id of PCI device class - * @property {string} VENDOR - Id of PCI device vendor - * @property {string} VMID - Id using this device, -1 if free - * @property {string} [DEVICE_NAME] - Name of PCI device - * @property {string} [VENDOR_NAME] - Name of PCI device vendor * @property {string} [CLASS_NAME] - Name of PCI device class + * @property {string} DEVICE - Id of PCI device + * @property {string} [DEVICE_NAME] - Name of PCI device + * @property {string} DOMAIN - Address domain + * @property {string} FUNCTION - Address function + * @property {string} NUMA_NODE - Numa node + * @property {string} SHORT_ADDRESS - Short address + * @property {string} SLOT - Address slot + * @property {string} TYPE - Type + * @property {string} VENDOR - Id of PCI device vendor + * @property {string} [VENDOR_NAME] - Name of PCI device vendor + * @property {string|number} VMID - Id using this device, -1 if free + */ + +/** + * @typedef {object} Core - Core + * @property {string} ID - + * @property {string} CPUS - + * @property {string} DEDICATED - + * @property {string} FREE - + */ + +/** + * @typedef {object} HugePage - HugePage + * @property {string} FREE - + * @property {string} SIZE - + * @property {string} USAGE - + * @property {string} DEDICATED - + */ + +/** + * @typedef {object} NumaNode - Numa node + * @property {string|number} NODE_ID - + * @property {Core|Core[]} CORE - + * @property {HugePage|HugePage[]} HUGEPAGE - + * @property {object} MEMORY - + * @property {string} MEMORY.DISTANCE - + * @property {string|number} MEMORY.FREE - + * @property {string|number} MEMORY.TOTAL - + * @property {string|number} MEMORY.USAGE - + * @property {string|number} MEMORY.USED - + */ + +/** + * @typedef Host + * @property {string|number} ID - Id + * @property {string} NAME - Name + * @property {string|number} STATE - State + * @property {string|number} PREV_STATE - Previously state + * @property {string} IM_MAD - Name of the Information Manager + * @property {string} VM_MAD - Name of the VM Manager + * @property {string|number} CLUSTER_ID - Cluster id + * @property {string} CLUSTER - Cluster name + * @property {object} HOST_SHARE - Host shared information + * @property {string|number} HOST_SHARE.MEM_USAGE - Memory used by all VMs running in the host + * @property {string|number} HOST_SHARE.CPU_USAGE - CPU used by all VMs running in the host + * @property {string|number} HOST_SHARE.TOTAL_MEM - Maximum memory that could be used for VMs + * @property {string|number} HOST_SHARE.TOTAL_CPU - Number of CPU’s multiplied by 100. For example, a 16 cores machine will have a value of 1600 + * @property {string|number} HOST_SHARE.MAX_MEM - Total memory in the host + * @property {string|number} HOST_SHARE.MAX_CPU - Percentage, Total CPU in the host (cores * 100) + * @property {string|number} HOST_SHARE.RUNNING_VMS - Running VMs + * @property {string|number} HOST_SHARE.VMS_THREAD - Thread VMs + * @property {object} HOST_SHARE.DATASTORES - Datastores information + * @property {string|number} HOST_SHARE.DATASTORES.DISK_USAGE - Disk used by all datastores + * @property {string|number} HOST_SHARE.DATASTORES.FREE_DISK - Free disk in the datastores + * @property {string|number} HOST_SHARE.DATASTORES.MAX_DISK - Maximum of disk in the datastores + * @property {string|number} HOST_SHARE.DATASTORES.USED_DISK - Used disk + * @property {{ PCI: PciDevice|PciDevice[] }} HOST_SHARE.PCI_DEVICES - List of PCI devices + * @property {{ NODE: NumaNode|NumaNode[] }} HOST_SHARE.NUMA_NODES - List of NUMA nodes + * @property {{ ID: string|string[] }} VMS - List of VM ids + * @property {object} TEMPLATE - Host template + * @property {string} [TEMPLATE.ARCH] - Architecture + * @property {string} [TEMPLATE.CPUSPEED] - CPU speed + * @property {string} [TEMPLATE.HOSTNAME] - Host name + * @property {string} [TEMPLATE.HYPERVISOR] - Hypervisor name + * @property {string} [TEMPLATE.IM_MAD] - Information manager + * @property {string} [TEMPLATE.VM_MAD] - VM manager + * @property {string} [TEMPLATE.KVM_CPU_MODEL] - KVM CPU model + * @property {string} [TEMPLATE.KVM_CPU_MODELS] - KVM CPU models + * @property {string} [TEMPLATE.VCENTER_CCR_REF] - vCenter information + * @property {string} [TEMPLATE.VCENTER_DS_REF] - vCenter information + * @property {string} [TEMPLATE.VCENTER_HOST] - vCenter information + * @property {string} [TEMPLATE.VCENTER_INSTANCE_ID] - vCenter information + * @property {string} [TEMPLATE.VCENTER_NAME] - vCenter information + * @property {string} [TEMPLATE.VCENTER_PASSWORD] - vCenter information + * @property {string} [TEMPLATE.VCENTER_RESOURCE_POOL_INFO] - vCenter information + * @property {string} [TEMPLATE.VCENTER_USER] - vCenter information + * @property {string} [TEMPLATE.VCENTER_VERSION] - vCenter information + * @property {string} [TEMPLATE.VERSION] - Version + * @property {object} MONITORING - Monitoring information + * @property {string} [MONITORING.TIMESTAMP] - Timestamp + * @property {object} [MONITORING.CAPACITY] - Capacity information + * @property {string} [MONITORING.CAPACITY.FREE_CPU] - Percentage, Free CPU as returned by the probes + * @property {string} [MONITORING.CAPACITY.FREE_MEMORY] - Free MEMORY returned by the probes + * @property {string} [MONITORING.CAPACITY.USED_CPU] - Percentage of CPU used by all host processes (including VMs) over a total of (cores * 100) + * @property {string} [MONITORING.CAPACITY.USED_MEMORY] - Memory used by all host processes (including VMs) over a total of MAX_MEM + * @property {object} [MONITORING.SYSTEM] - System information + * @property {object} [MONITORING.SYSTEM.NETRX] - Received bytes from the network + * @property {object} [MONITORING.SYSTEM.NETTX] - Sent bytes to the network */ /** @type {STATES.StateInfo[]} Host states */ @@ -87,7 +177,7 @@ export const HOST_ACTIONS = { REFRESH: ACTIONS.REFRESH, CREATE_DIALOG: 'create_dialog', RENAME: ACTIONS.RENAME, - ADD_TO_CLUSTER: 'addtocluster', + CHANGE_CLUSTER: 'change_cluster', ENABLE: 'enable', DISABLE: 'disable', OFFLINE: 'offline', diff --git a/src/fireedge/src/client/constants/image.js b/src/fireedge/src/client/constants/image.js index cbcfc882d6..d79b7196c2 100644 --- a/src/fireedge/src/client/constants/image.js +++ b/src/fireedge/src/client/constants/image.js @@ -14,7 +14,46 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ import * as STATES from 'client/constants/states' +import * as ACTIONS from 'client/constants/actions' import COLOR from 'client/constants/color' +// eslint-disable-next-line no-unused-vars +import { Permissions, LockInfo } from 'client/constants/common' +// eslint-disable-next-line no-unused-vars +import { DiskSnapshots } from 'client/constants/vm' + +/** + * @typedef Image + * @property {string} ID - Id + * @property {string} NAME - Name + * @property {string} UID - User id + * @property {string} UNAME - User name + * @property {string} GID - Group id + * @property {string} GNAME - Group name + * @property {string} STATE - State + * @property {string} PREV_STATE - Previous state + * @property {Permissions} PERMISSIONS - Permissions + * @property {LockInfo} [LOCK] - Lock information + * @property {IMAGE_TYPES_STR} TYPE - Type + * @property {DISK_TYPES_STR} DISK_TYPE - Disk type + * @property {string} PERSISTENT - Persistent + * @property {string} REGTIME - Registration time + * @property {string} SOURCE - Source + * @property {string} PATH - Path + * @property {string} FORMAT - Format + * @property {string} FS - Filesystem + * @property {string} SIZE - Size + * @property {string} RUNNING_VMS - Running VMs + * @property {string} CLONING_OPS - Cloning OPs + * @property {string} CLONING_ID - Cloning id + * @property {string} TARGET_SNAPSHOT - Target snapshot + * @property {string} DATASTORE_ID - Datastore id + * @property {string} DATASTORE - Datastore + * @property {{ ID: string|string[] }} VMS - VMs + * @property {{ ID: string|string[] }} CLONES - Clones + * @property {{ ID: string|string[] }} APP_CLONES - App clones + * @property {object} TEMPLATE - Template + * @property {DiskSnapshots} SNAPSHOTS - Snapshots information + */ /** @enum {string} Image type */ export const IMAGE_TYPES_STR = { @@ -121,3 +160,17 @@ export const IMAGE_STATES = [ color: COLOR.error.light, }, ] + +/** @enum {string} Image actions */ +export const IMAGE_ACTIONS = { + CREATE_DIALOG: 'create_dialog', + DELETE: 'delete', + + // INFORMATION + RENAME: ACTIONS.RENAME, + CHANGE_MODE: ACTIONS.CHANGE_MODE, + CHANGE_OWNER: ACTIONS.CHANGE_OWNER, + CHANGE_GROUP: ACTIONS.CHANGE_GROUP, + CHANGE_TYPE: 'chtype', + CHANGE_PERS: 'persistent', +} diff --git a/src/fireedge/src/client/constants/index.js b/src/fireedge/src/client/constants/index.js index 18f8b9c1b7..71edd034f3 100644 --- a/src/fireedge/src/client/constants/index.js +++ b/src/fireedge/src/client/constants/index.js @@ -113,12 +113,19 @@ export const RESOURCE_NAMES = { export * as T from 'client/constants/translates' export * as ACTIONS from 'client/constants/actions' export * as STATES from 'client/constants/states' +export * from 'client/constants/common' +export * from 'client/constants/quota' +export * from 'client/constants/scheduler' export * from 'client/constants/userInput' export * from 'client/constants/flow' export * from 'client/constants/provision' +export * from 'client/constants/user' +export * from 'client/constants/group' export * from 'client/constants/cluster' export * from 'client/constants/vm' export * from 'client/constants/vmTemplate' +export * from 'client/constants/network' +export * from 'client/constants/networkTemplate' export * from 'client/constants/host' export * from 'client/constants/image' export * from 'client/constants/marketplace' diff --git a/src/fireedge/src/client/constants/marketplace.js b/src/fireedge/src/client/constants/marketplace.js index 16922987eb..0d71ec1105 100644 --- a/src/fireedge/src/client/constants/marketplace.js +++ b/src/fireedge/src/client/constants/marketplace.js @@ -13,8 +13,35 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +import * as ACTIONS from 'client/constants/actions' import * as STATES from 'client/constants/states' import COLOR from 'client/constants/color' +// eslint-disable-next-line no-unused-vars +import { Permissions } from 'client/constants/common' + +/** + * @typedef Marketplace + * @property {string} ID - Id + * @property {string} NAME - Name + * @property {string} UID - User id + * @property {string} UNAME - User name + * @property {string} GID - Group id + * @property {string} GNAME - Group name + * @property {0|1} STATE - Possible STATE values are 0 (ENABLE) and 1 (DISABLE) + * @property {Permissions} PERMISSIONS - Permissions + * @property {string} MARKET_MAD - Market manager + * @property {string} ZONE_ID - Zone id + * @property {string} TOTAL_MB - Total capacity + * @property {string} FREE_MB - Free capacity + * @property {string} USED_MB - Used capacity + * @property {{ ID: string|string[] }} MARKETPLACEAPPS - Marketplace apps + * @property {object} TEMPLATE - Template information + * @property {string} [TEMPLATE.RESTRICTED_DIRS] - Restricted directory + * @property {string} [TEMPLATE.SAFE_DIRS] - Safe directory + * @property {string} [TEMPLATE.SHARED] - `YES` if it's shared + * @property {string} [TEMPLATE.TYPE] - Type + * @property {string} [TEMPLATE.TM_MAD] - TM manager + */ /** @type {STATES.StateInfo[]} Marketplace states */ export const MARKETPLACE_STATES = [ @@ -73,3 +100,15 @@ export const MARKETPLACE_APP_STATES = [ color: COLOR.debug.light, }, ] + +/** @enum {string} Datastore actions */ +export const MARKETPLACE_ACTIONS = { + CREATE_DIALOG: 'create_dialog', + DELETE: 'delete', + + // INFORMATION + RENAME: ACTIONS.RENAME, + CHANGE_MODE: ACTIONS.CHANGE_MODE, + CHANGE_OWNER: ACTIONS.CHANGE_OWNER, + CHANGE_GROUP: ACTIONS.CHANGE_GROUP, +} diff --git a/src/fireedge/src/client/constants/marketplaceApp.js b/src/fireedge/src/client/constants/marketplaceApp.js index 5e9d247941..04314a8d69 100644 --- a/src/fireedge/src/client/constants/marketplaceApp.js +++ b/src/fireedge/src/client/constants/marketplaceApp.js @@ -13,9 +13,44 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +// eslint-disable-next-line no-unused-vars +import { Permissions, LockInfo } from 'client/constants/common' +import * as ACTIONS from 'client/constants/actions' + +/** + * @typedef MarketplaceApp + * @property {string|number} ID - Id + * @property {string} NAME - Name + * @property {string} DESCRIPTION - Description + * @property {string} UID - User id + * @property {string|number} GID - Group id + * @property {string} GNAME - Group name + * @property {string} UNAME - User name + * @property {string} STATE - State + * @property {Permissions} PERMISSIONS - Permissions + * @property {string|number} TYPE - Type + * @property {LockInfo} [LOCK] - Lock information + * @property {string} MARKETPLACE_ID - Marketplace id + * @property {string} MARKETPLACE - Marketplace name + * @property {string} SIZE - Size + * @property {string} REGTIME - Registration time + * @property {string} ZONE_ID - Zone id + * @property {string} ORIGIN_ID - Origin id + * @property {string} SOURCE - Source + * @property {string} MD5 - MD5 + * @property {string} VERSION - Version + * @property {string} FORMAT - Format + * @property {object} TEMPLATE - Template information + * @property {string} [TEMPLATE.PUBLISHER] - Publisher + * @property {string} [TEMPLATE.TAGS] - Tags + * @property {string} [TEMPLATE.LINK] - Link + * @property {string} APPTEMPLATE64 - App template in base64 + */ + +/** @enum {string} Marketplace App actions */ export const MARKETPLACE_APP_ACTIONS = { - REFRESH: 'refresh', + REFRESH: ACTIONS.REFRESH, CREATE_DIALOG: 'create_dialog', - RENAME: 'rename', + RENAME: ACTIONS.RENAME, EXPORT: 'export', } diff --git a/src/fireedge/src/client/constants/network.js b/src/fireedge/src/client/constants/network.js new file mode 100644 index 0000000000..22acab2e93 --- /dev/null +++ b/src/fireedge/src/client/constants/network.js @@ -0,0 +1,121 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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-next-line no-unused-vars +import { Permissions, LockInfo } from 'client/constants/common' +import * as ACTIONS from 'client/constants/actions' + +/** + * @typedef ARLease + * @property {string} [IP] - IP + * @property {string} [IP6] - IP6 + * @property {string} [IP6_GLOBAL] - IP6 globa + * @property {string} [IP6_LINK] - IP6 link + * @property {string} [IP6_ULA] - IP6 ULA + * @property {string} MAC - MAC + * @property {string} [VM] - Virtual machine id + * @property {string} [VNET] - Virtual network id + * @property {string} [VROUTER] - Virtual router id + */ + +/** + * @typedef AddressRange + * @property {string} AR_ID - Address range id + * @property {string} [IP] - IP + * @property {string} MAC - MAC + * @property {string} SIZE - Size + * @property {AR_TYPES} TYPE - Type + * @property {string} USED_LEASES - Used leases + * @property {{ LEASE: ARLease|ARLease[] }} [LEASES] - Leases information + * @property {string} [GLOBAL_PREFIX] -Global prefix + * @property {string} [PARENT_NETWORK_AR_ID] - Parent address range id + * @property {string} [ULA_PREFIX] - ULA prefix + * @property {string} [VN_MAD] - Virtual network manager + * @property {string} [MAC_END] - MAC end + * @property {string} [IP_END] - IP end + * @property {string} [IP6_ULA] - IP6 ULA + * @property {string} [IP6_ULA_END] - IP6 ULA end + * @property {string} [IP6_GLOBAL] - IP6 global + * @property {string} [IP6_GLOBAL_END] - IP6 global end + * @property {string} [IP6] - IP6 + * @property {string} [IP6_END] - IP6 end + * @property {string} [PORT_START] - Port start + * @property {string} [PORT_SIZE] - Port size + */ + +/** + * @typedef VirtualNetwork + * @property {string} ID - Id + * @property {string} NAME - Name + * @property {string} UID - User id + * @property {string} UNAME - User name + * @property {string} GID - Group id + * @property {string} GNAME - Group name + * @property {Permissions} PERMISSIONS - Permissions + * @property {LockInfo} [LOCK] - Lock information + * @property {{ ID: string|string[] }} CLUSTERS - Clusters + * @property {{ ID: string|string[] }} VROUTERS - Virtual routers + * @property {string} BRIDGE - Bridge + * @property {string} [BRIDGE_TYPE] - Bridge type + * @property {string} PARENT_NETWORK_ID - Parent network id + * @property {string} VN_MAD - Virtual network manager + * @property {string} PHYDEV - Physical dev + * @property {string} [VLAN_ID] - VLAN id + * @property {string} [OUTER_VLAN_ID] - Outer VLAN id + * @property {string} VLAN_ID_AUTOMATIC - VLAN id automatic + * @property {string} OUTER_VLAN_ID_AUTOMATIC - Outer VLAN id automatic + * @property {string} USED_LEASES - Used leases + * @property {{ AR: AddressRange|AddressRange[] }} AR_POOL - Address range information + * @property {object} TEMPLATE - Template + * @property {string} [TEMPLATE.DNS] - DNS + * @property {string} [TEMPLATE.GATEWAY] - Gateway + * @property {string} [TEMPLATE.GATEWAY6] - Gateway6 + * @property {string} [TEMPLATE.GUEST_MTU] - Guest MTU + * @property {string} [TEMPLATE.IP6_METHOD] - IP6 method + * @property {string} [TEMPLATE.IP6_METRIC] - IP6 metric + * @property {string} [TEMPLATE.METHOD] - Method + * @property {string} [TEMPLATE.METRIC] - Metric + * @property {string} [TEMPLATE.NETWORK_ADDRESS] - Network address + * @property {string} [TEMPLATE.NETWORK_MASK] - Network mask + * @property {string} [TEMPLATE.SEARCH_DOMAIN] - Domain + * @property {string} [TEMPLATE.VCENTER_FROM_WILD] - vCenter information + * @property {string} [TEMPLATE.VCENTER_INSTANCE_ID] - vCenter information + * @property {string} [TEMPLATE.VCENTER_NET_REF] - vCenter information + * @property {string} [TEMPLATE.VCENTER_PORTGROUP_TYPE] - vCenter information + * @property {string} [TEMPLATE.VCENTER_TEMPLATE_REF] - vCenter information + */ + +/** @enum {string} Type of Addresses defined by this address range */ +export const AR_TYPES = { + NONE: 'NONE', + ETHER: 'ETHER', + IP4: 'IP4', + IP6: 'IP6', + IP6_STATIC: 'IP6_STATIC', + IP4_6: 'IP4_6', + IP4_6_STATIC: 'IP4_6_STATIC', +} + +/** @enum {string} Virtual network actions */ +export const VN_ACTIONS = { + CREATE_DIALOG: 'create_dialog', + DELETE: 'delete', + + // INFORMATION + RENAME: ACTIONS.RENAME, + CHANGE_MODE: ACTIONS.CHANGE_MODE, + CHANGE_OWNER: ACTIONS.CHANGE_OWNER, + CHANGE_GROUP: ACTIONS.CHANGE_GROUP, +} diff --git a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/List.js b/src/fireedge/src/client/constants/networkTemplate.js similarity index 54% rename from src/fireedge/src/client/components/Tabs/Vm/Snapshot/List.js rename to src/fireedge/src/client/constants/networkTemplate.js index f2869fb728..4f38c26a69 100644 --- a/src/fireedge/src/client/components/Tabs/Vm/Snapshot/List.js +++ b/src/fireedge/src/client/constants/networkTemplate.js @@ -13,24 +13,33 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import PropTypes from 'prop-types' +// eslint-disable-next-line no-unused-vars +import { Permissions, LockInfo } from 'client/constants/common' +import * as ACTIONS from 'client/constants/actions' -import SnapshotItem from 'client/components/Tabs/Vm/Snapshot/Item' +/** + * @typedef VNetworkTemplate + * @property {string} ID - Id + * @property {string} NAME - Name + * @property {string} UID - User id + * @property {string} UNAME - User name + * @property {string} GID - Group id + * @property {string} GNAME - Group name + * @property {string} REGTIME - Registration time + * @property {Permissions} PERMISSIONS - Permissions + * @property {LockInfo} [LOCK] - Lock information + * @property {object} TEMPLATE - Template + * @property {string} [TEMPLATE.VN_MAD] - Virtual network manager + */ -const SnapshotList = ({ snapshots, actions }) => ( -
- {snapshots.map((snapshot, idx) => ( - - ))} -
-) +/** @enum {string} Virtual network template actions */ +export const VN_TEMPLATE_ACTIONS = { + CREATE_DIALOG: 'create_dialog', + DELETE: 'delete', -SnapshotList.propTypes = { - snapshots: PropTypes.array, - actions: PropTypes.arrayOf(PropTypes.string), + // INFORMATION + RENAME: ACTIONS.RENAME, + CHANGE_MODE: ACTIONS.CHANGE_MODE, + CHANGE_OWNER: ACTIONS.CHANGE_OWNER, + CHANGE_GROUP: ACTIONS.CHANGE_GROUP, } - -SnapshotList.displayName = 'SnapshotList' - -export default SnapshotList diff --git a/src/fireedge/src/client/constants/quota.js b/src/fireedge/src/client/constants/quota.js new file mode 100644 index 0000000000..95d3351cb0 --- /dev/null +++ b/src/fireedge/src/client/constants/quota.js @@ -0,0 +1,70 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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. * + * ------------------------------------------------------------------------- */ + +/** + * @typedef {number|'-1'|'-2'} Quota + * - For each quota, there are two special limits + * ``-1``: the default quota will be used. + * ``-2``: Unlimited. + */ + +/** + * @typedef DatastoreQuota + * @property {Quota} ID - ID of the Datastore to set the quota for + * @property {Quota} IMAGES -Maximum number of images that can be created in the datastore + * @property {Quota} IMAGES_USED - {@link DatastoreQuota.IMAGES} + * @property {Quota} SIZE - Maximum size in MB that can be used in the datastore + * @property {Quota} SIZE_USED - {@link DatastoreQuota.SIZE} + */ + +/** + * @typedef NetworkQuota + * @property {Quota} ID - ID of the Network to set the quota for + * @property {Quota} LEASES - Maximum IPs that can be leased from the Network + * @property {Quota} LEASES_USED - {@link NetworkQuota.LEASES} + */ + +/** + * @typedef VmQuota + * @description Running quotas will be increased or decreased depending + * on the state of the Virtual Machine. The states in which the machine + * is counted as “Running” are `ACTIVE` , `HOLD`, `PENDING` and `CLONING`. + * @property {Quota} VMS - Maximum number of VMs that can be created + * @property {Quota} VMS_USED - {@link VmQuota.VMS} + * @property {Quota} RUNNING_VMS - Maximum number of VMs that can be running + * @property {Quota} RUNNING_VMS_USED - {@link VmQuota.RUNNING_VMS} + * @property {Quota} MEMORY - Maximum memory in MB that can be requested by user/group VMs + * @property {Quota} MEMORY_USED - {@link VmQuota.MEMORY} + * @property {Quota} RUNNING_MEMORY - Maximum memory in MB that can be running by user/group VMs + * @property {Quota} RUNNING_MEMORY_USED - {@link VmQuota.RUNNING_MEMORY} + * @property {Quota} CPU - Maximum CPU capacity that can be requested by user/group VMs + * @property {Quota} CPU_USED - {@link VmQuota.CPU} + * @property {Quota} RUNNING_CPU - Maximum CPU capacity that can be running by user/group VMs + * @property {Quota} RUNNING_CPU_USED - {@link VmQuota.RUNNING_CPU} + * @property {Quota} SYSTEM_DISK_SIZE - Maximum size (in MB) of system disks that can be requested by user/group VMs + * @property {Quota} SYSTEM_DISK_SIZE_USED - {@link VmQuota.SYSTEM_DISK_SIZE} + */ + +/** + * @typedef ImageQuota + * @type {object} + * @property {Quota} ID - ID of the Image to set the quota for + * @property {Quota} RVMS - Maximum VMs that can used this image at the same time + * @property {Quota} RVMS_USED - {@link ImageQuota.RVMS} + */ + +export const QUOTA_LIMIT_DEFAULT = '-1' +export const QUOTA_LIMIT_UNLIMITED = '-2' diff --git a/src/fireedge/src/client/constants/scheduler.js b/src/fireedge/src/client/constants/scheduler.js new file mode 100644 index 0000000000..5808f8cef3 --- /dev/null +++ b/src/fireedge/src/client/constants/scheduler.js @@ -0,0 +1,79 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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. * + * ------------------------------------------------------------------------- */ + +/** + * @typedef ScheduleAction + * @property {string} ACTION - Action to execute + * @property {string} ID - Id + * @property {string} TIME - Time + * @property {string} [WARNING] - Warning time + * @property {string} [ARGS] - Arguments separated by comma + * @property {string} [DAYS] - Days that the users wants execute the action. + * List separated by comma. Depend of {@link REPEAT}: + * - weekly: 0 (Sunday) to 6 (Saturday) + * - monthly: 1 to 31 + * - yearly: 1 to 365 + * - hourly: each ‘x’ hours + * @property {'0'|'1'|'2'} [END_TYPE] - Way to end the repetition: + * - `0`: never + * - `1`: repetition + * - `2`: date + * @property {string} [END_VALUE] - End value + * @property {'0'|'1'|'2'|'3'} [REPEAT] - Type of repetition: + * - `0`: weekly + * - `1`: monthly + * - `2`: yearly + * - `3`: hourly + */ + +/** + * @typedef CharterOptions + * @property {boolean} [edit] - If `true`, the charter can be edited in form + * @property {number|string} execute_after_days - Days to execute the action + * @property {number|string} warn_before_days - Alert a time before the action (in days) + */ + +/** @enum {string} Values to end an action */ +export const END_TYPE_VALUES = { + NEVER: '0', + REPETITION: '1', + DATE: '2', +} + +/** @enum {string} Values to repeat an action */ +export const REPEAT_VALUES = { + WEEKLY: '0', + MONTHLY: '1', + YEARLY: '2', + HOURLY: '3', +} + +/** @enum {string} Argument attributes */ +export const ARGS_TYPES = { + DISK_ID: 'DISK_ID', + NAME: 'NAME', + SNAPSHOT_ID: 'SNAPSHOT_ID', +} + +/** @enum {string} Period type */ +export const PERIOD_TYPES = { + YEARS: 'years', + MONTHS: 'months', + WEEKS: 'weeks', + DAYS: 'days', + HOURS: 'hours', + MINUTES: 'minutes', +} diff --git a/src/fireedge/src/client/constants/securityGroup.js b/src/fireedge/src/client/constants/securityGroup.js index 84e93c0778..35c5c9a70a 100644 --- a/src/fireedge/src/client/constants/securityGroup.js +++ b/src/fireedge/src/client/constants/securityGroup.js @@ -15,6 +15,21 @@ * ------------------------------------------------------------------------- */ import { T } from 'client/constants' +/** + * @typedef {object} SecurityGroupRule + * @property {number|string} SECURITY_GROUP_ID - ID + * @property {string} SECURITY_GROUP_NAME - Name + * @property {string} PROTOCOL - Protocol + * @property {string} RULE_TYPE - Rule type + * @property {number|string} ICMP_TYPE - ICMP type + * @property {number|string} [ICMPv6_TYPE] - ICMP v6 type + * @property {number|string} [RANGE] - Range + * @property {number|string} [NETWORK_ID] - Network id + * @property {number|string} [SIZE] - Network size + * @property {string} [IP] - Network IP + * @property {string} [MAC] - Network MAC + */ + /** * ICMP Codes for each ICMP type as in: * http://www.iana.org/assignments/icmp-parameters/ diff --git a/src/fireedge/src/client/constants/translates.js b/src/fireedge/src/client/constants/translates.js index a9eb94af2c..f40ff0cbd5 100644 --- a/src/fireedge/src/client/constants/translates.js +++ b/src/fireedge/src/client/constants/translates.js @@ -58,7 +58,7 @@ module.exports = { CurrentGroup: 'Current group: %s', CurrentOwner: 'Current owner: %s', Delete: 'Delete', - DeleteScheduledAction: 'Delete scheduled action: %s', + DeleteScheduleAction: 'Delete schedule action: %s', DeleteSomething: 'Delete: %s', Deploy: 'Deploy', Detach: 'Detach', @@ -102,6 +102,7 @@ module.exports = { Select: 'Select', SelectDatastore: 'Select a Datastore to store the resource', SelectDockerHubTag: 'Select DockerHub image tag (default latest)', + SelectYourActiveGroup: 'Select your active group', SelectGroup: 'Select a group', SelectHost: 'Select a host', SelectMarketplace: 'Select Marketplace', @@ -128,7 +129,7 @@ module.exports = { UnReschedule: 'Un-Reschedule', Unshare: 'Unshare', Update: 'Update', - UpdateScheduledAction: 'Update scheduled action: %s', + UpdateScheduleAction: 'Update schedule action: %s', /* questions */ Yes: 'Yes', @@ -137,7 +138,7 @@ module.exports = { /* Scheduling */ Action: 'Action', - ScheduledAction: 'Scheduled action', + ScheduleAction: 'Schedule action', Charter: 'Charter', PunctualAction: 'Punctual action', RelativeAction: 'Relative action', @@ -228,6 +229,7 @@ module.exports = { ProviderTemplate: 'Provider template', ProvisionTemplate: 'Provision template', ConfigureInputs: 'Configure inputs', + Log: 'Log', AddIP: 'Add IP', AddHost: 'Add Host', Cleanup: 'Cleanup', @@ -632,6 +634,15 @@ module.exports = { ExportAssociateApp: 'Export associated VM templates/images', ImportAssociateApp: 'Import associated VM templates/images', + /* Image schema */ + Limit: 'Limit', + BasePath: 'Base path', + + /* Image schema */ + FileSystemType: 'Filesystem type', + Persistent: 'Persistent', + RunningVMs: 'Running VMs', + /* User inputs */ UserInputs: 'User Inputs', UserInputsConcept: ` diff --git a/src/fireedge/src/client/constants/user.js b/src/fireedge/src/client/constants/user.js new file mode 100644 index 0000000000..89156157d7 --- /dev/null +++ b/src/fireedge/src/client/constants/user.js @@ -0,0 +1,66 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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-next-line prettier/prettier, no-unused-vars +import { VmQuota, NetworkQuota, DatastoreQuota, ImageQuota } from 'client/constants/quota' +import * as ACTIONS from 'client/constants/actions' + +/** + * @typedef LoginToken + * @property {string} TOKEN - Token + * @property {string|number} EXPIRATION_TIME - Expiration time + * @property {string} EGID - ?? + */ + +/** + * @typedef User + * @property {string|number} ID - Id + * @property {string} NAME - Name + * @property {string|number} GID - Group id + * @property {string} GNAME - Group name + * @property {{ ID: string[] }} GROUPS - List of group ids + * @property {string} PASSWORD - Password + * @property {string} AUTH_DRIVER - Driver to authenticate + * @property {'0'|'1'} ENABLED - If `0` the user is enabled + * @property {LoginToken|LoginToken[]} [LOGIN_TOKEN] - Token to login + * @property {object} TEMPLATE - Template + * @property {string} [TEMPLATE.TOKEN_PASSWORD] - Password token + * @property {{ DATASTORE: DatastoreQuota|DatastoreQuota[] }} [DATASTORE_QUOTA] - Datastore quotas + * @property {{ NETWORK: NetworkQuota|NetworkQuota[] }} [NETWORK_QUOTA] - Network quotas + * @property {{ VM: VmQuota }} [VM_QUOTA] - VM quotas + * @property {{ IMAGE: ImageQuota|ImageQuota[] }} [IMAGE_QUOTA] - Image quotas + * @property {{ + * DATASTORE: DatastoreQuota|DatastoreQuota[], + * NETWORK: NetworkQuota|NetworkQuota[], + * VM: VmQuota, + * IMAGE: ImageQuota|ImageQuota[] + * }} [DEFAULT_USER_QUOTAS] - Default quotas + */ + +export const USER_ACTIONS = { + REFRESH: ACTIONS.REFRESH, + CREATE_DIALOG: 'create_dialog', + QUOTAS_DIALOG: 'quotas_dialog', + GROUPS_DIALOG: 'groups_dialog', + UPDATE_PASSWORD: 'update_password', + DELETE: 'delete', + EDIT_ADMINS: 'edit_admins', + LOGIN_TOKEN: 'login_token', + TFA: 'two_factor_auth', + CHANGE_GROUP: ACTIONS.CHANGE_GROUP, + CHANGE_AUTH: 'change_authentication', + ENABLE: 'enable', + DISABLE: 'disable', +} diff --git a/src/fireedge/src/client/constants/vm.js b/src/fireedge/src/client/constants/vm.js index adb379f8ec..81d3471b3f 100644 --- a/src/fireedge/src/client/constants/vm.js +++ b/src/fireedge/src/client/constants/vm.js @@ -16,6 +16,205 @@ import * as STATES from 'client/constants/states' import * as ACTIONS from 'client/constants/actions' import COLOR from 'client/constants/color' +// eslint-disable-next-line no-unused-vars +import { Permissions, LockInfo } from 'client/constants/common' +// eslint-disable-next-line no-unused-vars +import { ScheduleAction } from 'client/constants/scheduler' + +/** + * @typedef {object} Disk + * @property {string} [VCENTER_DS_REF] - + * @property {string} [VCENTER_INSTANCE_ID] - + */ + +/** + * @typedef {object} Nic + * @property {string} [VCENTER_INSTANCE_ID] - + * @property {string} [VCENTER_NET_REF] - + * @property {string} [VCENTER_PORTGROUP_TYPE] - + */ + +/** + * @typedef {object} NicAlias + * @property {string} ALIAS_ID - + * @property {string} PARENT - + * @property {string} PARENT_ID - + * @property {string} [VCENTER_INSTANCE_ID] - + * @property {string} [VCENTER_NET_REF] - + * @property {string} [VCENTER_PORTGROUP_TYPE] - + */ + +/** + * @typedef {object} DiskSize + * @property {string|number} ID - + * @property {string|number} SIZE - + */ + +/** + * @typedef {object} Graphics + * @property {string|number} LISTEN - + * @property {string} RANDOM_PASSW - + * @property {string} TYPE - + */ + +/** + * @typedef {object} HistoryRecord + * @property {string|number} OID - + * @property {string|number} SEQ - + * @property {string} HOSTNAME - + * @property {string|number} HID - + * @property {string|number} CID - + * @property {string|number} STIME - + * @property {string|number} ETIME - + * @property {string} VM_MAD - + * @property {string} TM_MAD - + * @property {string|number} DS_ID - + * @property {string|number} PSTIME - + * @property {string|number} PETIME - + * @property {string|number} RSTIME - + * @property {string|number} RETIME - + * @property {string|number} ESTIME - + * @property {string|number} EETIME - + * @property {VM_ACTIONS} ACTION - + * @property {string|number} UID - + * @property {string|number} GID - + * @property {string|number} REQUEST_ID - + */ + +/** + * @typedef {object} HistoryShortRecord + * @property {string|number} OID - + * @property {string|number} SEQ - + * @property {string} HOSTNAME - + * @property {string|number} HID - + * @property {string|number} CID - + * @property {string|number} DS_ID - + * @property {VM_ACTIONS} ACTION - + */ + +/** + * @typedef {object} DiskSnapshots + * @property {string|number} ALLOW_ORPHANS - + * @property {string|number} CURRENT_BASE - + * @property {string|number} DISK_ID - + * @property {string|number} NEXT_SNAPSHOT - + * @property {DiskSnapshot|DiskSnapshot[]} [SNAPSHOT] - + */ + +/** + * @typedef {object} DiskSnapshot + * @property {string|number} ID - + * @property {string|number} DATE - + * @property {string|number} PARENT - + * @property {string|number} SIZE - + * @property {string} [NAME] - + * @property {string} [ACTIVE] - + * @property {string} [CHILDREN] - + */ + +/** + * @typedef {object} Snapshot + * @property {string} SNAPSHOT_ID - + * @property {string} NAME - + * @property {string} TIME - + * @property {string} HYPERVISOR_ID - + * @property {string} SYSTEM_DISK_SIZE - + * @property {string} [ACTIVE] - + * @property {string} [ACTION] - + */ + +/** + * @typedef {object} VM + * @property {string|number} ID - Id + * @property {string} NAME - Name + * @property {string|number} UID - User id + * @property {string|number} GID - Group id + * @property {string} UNAME - User name + * @property {string} GNAME - Group name + * @property {Permissions} PERMISSIONS - Permissions + * @property {string|number} LAST_POLL - Last poll + * @property {string|number} STATE - Current state + * @property {string|number} LCM_STATE - Current LCM state + * @property {string|number} PREV_STATE - Previous state + * @property {string|number} PREV_LCM_STATE - Previous LCM state + * @property {string|number} STIME - Start time + * @property {string|number} ETIME - End time + * @property {string|number} DEPLOY_ID - Deploy id + * @property {LockInfo} [LOCK] - Lock information + * @property {object} MONITORING - Monitoring information + * @property {number} [MONITORING.CPU] - Percentage of 1 CPU consumed (two fully consumed cpu is 2.0) + * @property {number} [MONITORING.DISKRDBYTES] - Amount of bytes read from disk + * @property {number} [MONITORING.DISKRDIOPS] - Number of IO read operations + * @property {number} [MONITORING.DISKWRBYTES] - Amount of bytes written to disk + * @property {number} [MONITORING.DISKWRIOPS] - Number of IO write operations + * @property {DiskSize|DiskSize[]} [MONITORING.DISK_SIZE] - Disk size details + * @property {number} [MONITORING.ID] - ID of the VM + * @property {number} [MONITORING.MEMORY] - Consumption in kilobytes + * @property {number} [MONITORING.NETRX] - Received bytes from the network + * @property {number} [MONITORING.NETTX] - Sent bytes to the network + * @property {number} [MONITORING.TIMESTAMP] - Exact time when monitoring info were retrieved + * @property {string} [MONITORING.VCENTER_ESX_HOST] - vCenter information + * @property {string} [MONITORING.VCENTER_GUEST_STATE] - vCenter information + * @property {string} [MONITORING.VCENTER_RP_NAME] - vCenter information + * @property {string} [MONITORING.VCENTER_VMWARETOOLS_RUNNING_STATUS] - vCenter information + * @property {string} [MONITORING.VCENTER_VMWARETOOLS_VERSION] - vCenter information + * @property {string} [MONITORING.VCENTER_VMWARETOOLS_VERSION_STATUS] - vCenter information + * @property {string} [MONITORING.VCENTER_VM_NAME] - vCenter information + * @property {object} TEMPLATE - Template information + * @property {string} [TEMPLATE.AUTOMATIC_DS_REQUIREMENTS] - + * @property {string} [TEMPLATE.AUTOMATIC_NIC_REQUIREMENTS] - + * @property {string} [TEMPLATE.AUTOMATIC_REQUIREMENTS] - + * @property {string} [TEMPLATE.CLONING_TEMPLATE_ID] - + * @property {string} [TEMPLATE.CONTEXT] - + * @property {string} [TEMPLATE.CPU] - + * @property {string} [TEMPLATE.CPU_COST] - + * @property {Disk|Disk[]} [TEMPLATE.DISK] - + * @property {string} [TEMPLATE.DISK_COST] - + * @property {string} [TEMPLATE.EMULATOR] - + * @property {any} [TEMPLATE.FEATURES] - + * @property {any} [TEMPLATE.HYPERV_OPTIONS] - + * @property {Graphics} [TEMPLATE.GRAPHICS] - + * @property {string} [TEMPLATE.IMPORTED] - + * @property {any} [TEMPLATE.INPUT] - + * @property {string} [TEMPLATE.MEMORY] - + * @property {string} [TEMPLATE.MEMORY_COST] - + * @property {string} [TEMPLATE.MEMORY_MAX] - + * @property {string} [TEMPLATE.MEMORY_SLOTS] - + * @property {Nic|Nic[]} [TEMPLATE.NIC] - + * @property {NicAlias|NicAlias[]} [TEMPLATE.NIC_ALIAS] - + * @property {any} [TEMPLATE.NIC_DEFAULT] - + * @property {any} [TEMPLATE.NUMA_NODE] - + * @property {any} [TEMPLATE.OS] - + * @property {any} [TEMPLATE.PCI] - + * @property {any} [TEMPLATE.RAW] - + * @property {ScheduleAction|ScheduleAction[]} [TEMPLATE.SCHED_ACTION] - + * @property {Snapshot|Snapshot[]} [TEMPLATE.SNAPSHOT] - + * @property {any} [TEMPLATE.SECURITY_GROUP_RULE] - + * @property {any} [TEMPLATE.SPICE_OPTIONS] - + * @property {string} [TEMPLATE.SUBMIT_ON_HOLD] - + * @property {string} [TEMPLATE.TEMPLATE_ID] - + * @property {string} TEMPLATE.TM_MAD_SYSTEM - + * @property {any} [TEMPLATE.TOPOLOGY] - + * @property {string} [TEMPLATE.VCPU] - + * @property {string} [TEMPLATE.VCPU_MAX] - + * @property {object|object[]} [TEMPLATE.VMGROUP] - + * @property {string} TEMPLATE.VMID - + * @property {string} [TEMPLATE.VROUTER_ID] - + * @property {string} [TEMPLATE.VROUTER_KEEPALIVED_ID] - + * @property {string} [TEMPLATE.VROUTER_KEEPALIVED_PASSWORD] - + * @property {object} USER_TEMPLATE - + * @property {string} [USER_TEMPLATE.ERROR] - + * @property {string} [USER_TEMPLATE.HYPERVISOR] - + * @property {string} [USER_TEMPLATE.LOGO] - + * @property {string} [USER_TEMPLATE.INFO] - + * @property {string} [USER_TEMPLATE.SCHED_REQUIREMENTS] - + * @property {string} [USER_TEMPLATE.VCENTER_CCR_REF] - + * @property {string} [USER_TEMPLATE.VCENTER_DS_REF] - + * @property {string} [USER_TEMPLATE.VCENTER_INSTANCE_ID] - + * @property {object} HISTORY_RECORDS - History + * @property {HistoryRecord|HistoryRecord[]} [HISTORY_RECORDS.HISTORY] - History Records + * @property {DiskSnapshots|DiskSnapshots[]} [SNAPSHOTS] - + */ /** @type {STATES.StateInfo[]} Virtual machine states */ export const VM_STATES = [ diff --git a/src/fireedge/src/client/constants/vmTemplate.js b/src/fireedge/src/client/constants/vmTemplate.js index d6b465af42..522b21835a 100644 --- a/src/fireedge/src/client/constants/vmTemplate.js +++ b/src/fireedge/src/client/constants/vmTemplate.js @@ -14,6 +14,26 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ import * as ACTIONS from 'client/constants/actions' +// eslint-disable-next-line no-unused-vars +import { Permissions, LockInfo } from 'client/constants/common' + +/** + * @typedef {object} VmTemplate + * @property {string|number} ID - Id + * @property {string} NAME - Name + * @property {string|number} UID - User id + * @property {string|number} GID - Group id + * @property {string} UNAME - User name + * @property {string} GNAME - Group name + * @property {Permissions} PERMISSIONS - Permissions + * @property {LockInfo} [LOCK] - Lock information + * @property {string|number} REGTIME - Registration time + * @property {object} TEMPLATE - Template information + * @property {string} [TEMPLATE.CONTEXT] - Context + * @property {string} [TEMPLATE.VCENTER_CCR_REF] - vCenter information + * @property {string} [TEMPLATE.VCENTER_INSTANCE_ID] - vCenter information + * @property {string} [TEMPLATE.VCENTER_TEMPLATE_REF] - vCenter information + */ export const VM_TEMPLATE_ACTIONS = { REFRESH: ACTIONS.REFRESH, diff --git a/src/fireedge/src/client/constants/zone.js b/src/fireedge/src/client/constants/zone.js index c4039a24eb..9df60ddb66 100644 --- a/src/fireedge/src/client/constants/zone.js +++ b/src/fireedge/src/client/constants/zone.js @@ -13,9 +13,33 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +import * as ACTIONS from 'client/constants/actions' import * as STATES from 'client/constants/states' import COLOR from 'client/constants/color' +/** + * @typedef ZoneServer + * @property {string} ID - Id + * @property {string} NAME - Name + * @property {string} ENDPOINT - RPC endpoint + * @property {string} [STATE] - State + * @property {string} [TERM] - Term + * @property {string} [VOTEDFOR] - Voted for + * @property {string} [COMMIT] - Commit + * @property {string} [LOG_INDEX] - Log index + * @property {string} [FEDLOG_INDEX] - Federation log index + */ + +/** + * @typedef Zone + * @property {string} ID - Id + * @property {string} NAME - Name + * @property {0|1} STATE - Possible STATE values are 0 (ENABLED) and 1 (DISABLED) + * @property {object} TEMPLATE - Template + * @property {string} TEMPLATE.ENDPOINT - Endpoint + * @property {{ SERVER: ZoneServer|ZoneServer[] }} SERVER_POOL - Server pool information + */ + /** @type {STATES.StateInfo[]} Zone states */ export const ZONE_STATES = [ { @@ -29,3 +53,11 @@ export const ZONE_STATES = [ color: COLOR.debug.main, }, ] + +/** @enum {string} Zone actions */ +export const ZONE_ACTIONS = { + CREATE_DIALOG: 'create_dialog', + DELETE: 'delete', + + RENAME: ACTIONS.RENAME, +} diff --git a/src/fireedge/src/client/containers/ApplicationsInstances/DialogInfo/dialog.js b/src/fireedge/src/client/containers/ApplicationsInstances/DialogInfo/dialog.js index 28746025b6..bcc8cd7d80 100644 --- a/src/fireedge/src/client/containers/ApplicationsInstances/DialogInfo/dialog.js +++ b/src/fireedge/src/client/containers/ApplicationsInstances/DialogInfo/dialog.js @@ -39,7 +39,7 @@ const CustomDialog = ({ title, handleClose, children }) => { maxWidth="xl" scroll="paper" PaperProps={{ - style: { + sx: { height: isMobile ? '100%' : '90%', width: isMobile ? '100%' : '90%', }, @@ -48,7 +48,7 @@ const CustomDialog = ({ title, handleClose, children }) => { {title} { - fetchRequest() - }, []) - - // const list = useMemo(() => ( - // applications.length > 0 - // ? applications?.filter(({ TEMPLATE: { BODY: { state } } }) => - // APPLICATION_STATES[state]?.name !== DONE - // ) - // : applications - // ), [applications]) + const { + data: applications = [], + refetch, + error, + isLoading, + } = useGetServicesQuery() return ( @@ -55,8 +41,8 @@ function ApplicationsInstances() { hasReloadButton reloadButtonProps={{ 'data-cy': 'refresh-application-list', - onClick: () => fetchRequest(undefined, { reload: true, delay: 500 }), - isSubmitting: Boolean(loading || reloading), + onClick: () => refetch(), + isSubmitting: isLoading, }} /> @@ -65,7 +51,6 @@ function ApplicationsInstances() { ) : ( ({ diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Clusters/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Clusters/index.js index 6a954586bb..406fbedd09 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Clusters/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Clusters/index.js @@ -14,10 +14,10 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useCallback } from 'react' +import { useCallback } from 'react' -import { useListForm, useFetch } from 'client/hooks' -import { useCluster, useClusterApi } from 'client/features/One' +import { useListForm } from 'client/hooks' +import { useGetClustersQuery } from 'client/features/OneApi/cluster' import { ListCards } from 'client/components/List' import { ClusterCard, EmptyCard } from 'client/components/Cards' @@ -31,24 +31,17 @@ const Clusters = () => ({ label: T.WhereWillItRun, resolver: STEP_FORM_SCHEMA, content: useCallback(({ data, setFormData }) => { - const clusters = useCluster() - const { getClusters } = useClusterApi() - - const { fetchRequest, loading } = useFetch(getClusters) + const { data: clusters = [], isLoading } = useGetClustersQuery() const { handleSelect, handleUnselect } = useListForm({ key: STEP_ID, setList: setFormData, }) - useEffect(() => { - fetchRequest() - }, []) - return ( } CardComponent={ClusterCard} cardsProps={({ value: { ID } }) => { diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Networking/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Networking/index.js index 2008b8d633..2a4589c383 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Networking/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Networking/index.js @@ -14,13 +14,10 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useState, useEffect, useCallback } from 'react' - +import { useState, useCallback } from 'react' import { useWatch } from 'react-hook-form' import { useListForm } from 'client/hooks' -import { useVNetworkApi, useVNetworkTemplateApi } from 'client/features/One' - import FormWithSchema from 'client/components/Forms/FormWithSchema' import { ListCards } from 'client/components/List' import { DialogForm } from 'client/components/Dialogs' @@ -40,9 +37,6 @@ const Networks = () => ({ const form = useWatch({}) const [showDialog, setShowDialog] = useState(false) - const { getVNetworks } = useVNetworkApi() - const { getVNetworkTemplates } = useVNetworkTemplateApi() - const { editingData, handleSave, handleEdit, handleClone, handleRemove } = useListForm({ key: STEP_ID, @@ -51,11 +45,6 @@ const Networks = () => ({ defaultValue: NETWORK_FORM_SCHEMA.default(), }) - useEffect(() => { - getVNetworks() - getVNetworkTemplates() - }, []) - return ( <> { - const vNetworks = useVNetwork() - const vNetworksTemplates = useVNetworkTemplate() + const { data: vNetworks = [] } = useGetVNetworksQuery() + const { data: vNetworksTemplates = [] } = useGetVNTemplatesQuery() const values = isNetworkSelector(dependValue) ? vNetworks diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Policies/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Policies/index.js index be8fb724e2..dd06ccd2c3 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Policies/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Policies/index.js @@ -139,7 +139,7 @@ const Policies = () => ({ diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Template/List/MarketApps.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Template/List/MarketApps.js index ae8dec0326..302235fbe8 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Template/List/MarketApps.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/Steps/Tiers/Steps/Template/List/MarketApps.js @@ -14,22 +14,16 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useEffect } from 'react' import PropTypes from 'prop-types' -import { useMarketplaceApp, useMarketplaceAppApi } from 'client/features/One' +import { useGetMarketplaceAppsQuery } from 'client/features/OneApi/marketplaceApp' import Search from 'client/components/Search' import { SelectCard } from 'client/components/Cards' const sortByID = (a, b) => a.ID - b.ID const ListMarketApp = ({ backButton, currentValue, handleSetData }) => { - const apps = useMarketplaceApp() - const { getMarketplaceApps } = useMarketplaceAppApi() - - useEffect(() => { - getMarketplaceApps() - }, []) + const { data: apps = [] } = useGetMarketplaceAppsQuery() return ( a.ID - b.ID const ListTemplates = ({ backButton, currentValue, handleSetData }) => { - const templates = useVmTemplate() - const { getTemplates } = useVmTemplateApi() - - useEffect(() => { - getTemplates() - }, []) + const { data: templates = [] } = useGetTemplatesQuery() return ( , + button: , content: ListTemplates, }, { id: 'app', - button: , + button: , content: ListMarketApps, }, { diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js index 9fbf599199..dbd79b49f5 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Create/index.js @@ -14,7 +14,7 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useEffect } from 'react' +/* import { useEffect } from 'react' import { Redirect, useHistory, useParams } from 'react-router-dom' import { LinearProgress, Container } from '@mui/material' @@ -25,12 +25,11 @@ import FormStepper from 'client/components/FormStepper' import Steps from 'client/containers/ApplicationsTemplates/Form/Create/Steps' import { PATH } from 'client/apps/sunstone/routesFlow' -import { useFetch } from 'client/hooks' -import { useApplicationTemplateApi } from 'client/features/One' -import { parseApplicationToForm, parseFormToApplication } from 'client/utils' +import { useGetServiceTemplateQuery } from 'client/features/OneApi/serviceTemplate' +import { parseApplicationToForm, parseFormToApplication } from 'client/utils' */ function ApplicationsTemplatesCreateForm() { - const history = useHistory() + /* const history = useHistory() const { id } = useParams() const { steps, defaultValues, resolvers } = Steps() @@ -83,13 +82,14 @@ function ApplicationsTemplatesCreateForm() { ) : ( - ) + ) */ + return <>{'Create service template form WIP'} } export default ApplicationsTemplatesCreateForm diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/index.js index a5080f7cc2..a767605729 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/index.js @@ -14,11 +14,9 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useCallback } from 'react' - +import { useCallback } from 'react' import { Divider, Paper, Typography } from '@mui/material' -import { useVNetworkApi, useVNetworkTemplateApi } from 'client/features/One' import FormWithSchema from 'client/components/Forms/FormWithSchema' import { T } from 'client/constants' @@ -31,32 +29,28 @@ const Networks = () => ({ label: T.ConfigureNetworking, resolver: STEP_FORM_SCHEMA, optionsValidate: { abortEarly: false }, - content: useCallback(({ data }) => { - const { getVNetworks } = useVNetworkApi() - const { getVNetworkTemplates } = useVNetworkTemplateApi() - - useEffect(() => { - getVNetworks() - getVNetworkTemplates() - }, []) - - return data?.map(({ id, name, description }, index) => ( - - {name} - {description && {description}} - - - - )) - }, []), + content: useCallback( + ({ data }) => + data?.map(({ id, name, description }, index) => ( + + {name} + {description && ( + {description} + )} + + + + )), + [] + ), }) export default Networks diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/schema.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/schema.js index 6ad464aad7..84c14d7386 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/schema.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/Steps/Networking/schema.js @@ -15,7 +15,8 @@ * ------------------------------------------------------------------------- */ import * as yup from 'yup' import { INPUT_TYPES } from 'client/constants' -import { useVNetwork, useVNetworkTemplate } from 'client/features/One' +import { useGetVNetworksQuery } from 'client/features/OneApi/network' +import { useGetVNTemplatesQuery } from 'client/features/OneApi/networkTemplate' import { getValidationFromFields } from 'client/utils' const SELECT = { @@ -50,8 +51,8 @@ const ID_VNET = { type: INPUT_TYPES.AUTOCOMPLETE, dependOf: TYPE.name, values: (dependValue) => { - const vNetworks = useVNetwork() - const vNetworksTemplates = useVNetworkTemplate() + const { data: vNetworks = [] } = useGetVNetworksQuery() + const { data: vNetworksTemplates = [] } = useGetVNTemplatesQuery() const type = TYPES_NETWORKS.find(({ value }) => value === dependValue) diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/index.js index 4fec24fcc1..c63a0c49e1 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/Form/Deploy/index.js @@ -14,15 +14,15 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useMemo, useState } from 'react' +/* import { useEffect, useMemo, useState } from 'react' import PropTypes from 'prop-types' import { CircularProgress, Backdrop } from '@mui/material' import makeStyles from '@mui/styles/makeStyles' import { useFetchAll } from 'client/hooks' -import { useApplicationTemplateApi } from 'client/features/One' import { useGeneralApi } from 'client/features/General' +import { } from 'client/features/OneApi/serviceTemplate' import { DialogForm } from 'client/components/Dialogs' import FormStepper from 'client/components/FormStepper' @@ -37,10 +37,12 @@ const useStyles = makeStyles((theme) => ({ zIndex: theme.zIndex.appBar, color: theme.palette.common.white, }, -})) +})) */ -const DeployForm = ({ applicationTemplate, handleCancel }) => { - const classes = useStyles() +const DeployForm = () => ( + // const DeployForm = ({ applicationTemplate, handleCancel }) => ( + + /* const classes = useStyles() const [vmTemplates, setVmTemplates] = useState([]) const { enqueueInfo } = useGeneralApi() @@ -110,10 +112,12 @@ const DeployForm = ({ applicationTemplate, handleCancel }) => { > - ) -} + ) */ -DeployForm.propTypes = { + <>{'Deploy service template form WIP'} +) + +/* DeployForm.propTypes = { applicationTemplate: PropTypes.object.isRequired, handleCancel: PropTypes.func, } @@ -121,6 +125,6 @@ DeployForm.propTypes = { DeployForm.defaultProps = { applicationTemplate: undefined, handleCancel: undefined, -} +} */ export default DeployForm diff --git a/src/fireedge/src/client/containers/ApplicationsTemplates/index.js b/src/fireedge/src/client/containers/ApplicationsTemplates/index.js index 877bd668eb..5fbf4e9632 100644 --- a/src/fireedge/src/client/containers/ApplicationsTemplates/index.js +++ b/src/fireedge/src/client/containers/ApplicationsTemplates/index.js @@ -14,21 +14,15 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useState } from 'react' - +import { useState } from 'react' import { useHistory, generatePath } from 'react-router-dom' import { Container, Box } from '@mui/material' import { PATH } from 'client/apps/sunstone/routesFlow' -import { useFetch } from 'client/hooks' -import { - useApplicationTemplate, - useApplicationTemplateApi, -} from 'client/features/One' - +import { useGetServiceTemplatesQuery } from 'client/features/OneApi/serviceTemplate' import DeployForm from 'client/containers/ApplicationsTemplates/Form/Deploy' -import { ListHeader, ListCards } from 'client/components/List' import AlertError from 'client/components/Alerts/Error' +import { ListHeader, ListCards } from 'client/components/List' import { ApplicationTemplateCard } from 'client/components/Cards' import { T } from 'client/constants' @@ -36,16 +30,12 @@ function ApplicationsTemplates() { const history = useHistory() const [showDialog, setShowDialog] = useState(false) - const applicationsTemplates = useApplicationTemplate() - const { getApplicationsTemplates } = useApplicationTemplateApi() - - const { error, fetchRequest, loading, reloading } = useFetch( - getApplicationsTemplates - ) - - useEffect(() => { - fetchRequest() - }, []) + const { + data: applicationsTemplates = [], + refetch, + error, + isLoading, + } = useGetServiceTemplatesQuery() return ( @@ -54,8 +44,8 @@ function ApplicationsTemplates() { hasReloadButton reloadButtonProps={{ 'data-cy': 'refresh-application-template-list', - onClick: () => fetchRequest(undefined, { reload: true, delay: 500 }), - isSubmitting: Boolean(loading || reloading), + onClick: () => refetch(), + isSubmitting: isLoading, }} addButtonProps={{ 'data-cy': 'create-application-template', @@ -68,7 +58,6 @@ function ApplicationsTemplates() { ) : ( ({ diff --git a/src/fireedge/src/client/containers/Dashboard/Provision/index.js b/src/fireedge/src/client/containers/Dashboard/Provision/index.js index 98b239c6b0..061d136fb3 100644 --- a/src/fireedge/src/client/containers/Dashboard/Provision/index.js +++ b/src/fireedge/src/client/containers/Dashboard/Provision/index.js @@ -13,29 +13,32 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useEffect, JSXElementConstructor } from 'react' -import { Container, Box, Grid } from '@mui/material' +import { memo, ReactElement } from 'react' +import PropTypes from 'prop-types' +import { Container, Box, Grid, CircularProgress } from '@mui/material' +import { + Server as ClusterIcon, + HardDrive as HostIcon, + Folder as DatastoreIcon, + NetworkAlt as NetworkIcon, +} from 'iconoir-react' import { useAuth } from 'client/features/Auth' -import { useFetchAll } from 'client/hooks' -import { useProvisionApi, useProviderApi } from 'client/features/One' -import * as Widgets from 'client/components/Widgets' +import { useGetResourceQuery } from 'client/features/OneApi/provision' + +import { + TotalProviders, + TotalProvisionsByState, +} from 'client/components/Widgets' +import NumberEasing from 'client/components/NumberEasing' +import WavesCard from 'client/components/Cards/WavesCard' import { stringToBoolean } from 'client/models/Helper' +import { T } from 'client/constants' -/** @returns {JSXElementConstructor} Provision dashboard container */ +/** @returns {ReactElement} Provision dashboard container */ function ProvisionDashboard() { - const { status, fetchRequestAll, STATUS } = useFetchAll() - const { INIT, PENDING } = STATUS - - const { getProvisions } = useProvisionApi() - const { getProviders } = useProviderApi() - const { settings: { disableanimations } = {} } = useAuth() - useEffect(() => { - fetchRequestAll([getProviders(), getProvisions()]) - }, []) - return ( - - + + + + - + - + @@ -70,4 +90,33 @@ function ProvisionDashboard() { ) } +const ResourceWidget = memo(({ resource, ...props }) => { + const { data, isLoading } = useGetResourceQuery({ resource }) + const total = `${data?.length ?? 0}` + + return ( + + + ) : ( + + ) + } + {...props} + /> + + ) +}) + +ResourceWidget.displayName = 'ResourceWidget' + +ResourceWidget.propTypes = { + resource: PropTypes.string, + text: PropTypes.string, + bgColor: PropTypes.string, + icon: PropTypes.any, +} + export default ProvisionDashboard diff --git a/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js b/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js index 7e8d1fc7e1..7199dc04fa 100644 --- a/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js +++ b/src/fireedge/src/client/containers/Dashboard/Sunstone/index.js @@ -13,36 +13,30 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useEffect, JSXElementConstructor } from 'react' -import { Container, Box, Grid } from '@mui/material' +import { memo, ReactElement } from 'react' +import PropTypes from 'prop-types' +import { Container, Box, CircularProgress, Grid } from '@mui/material' +import { + User as UserIcon, + Group as GroupIcon, + Archive as ImageIcon, + NetworkAlt as NetworkIcon, +} from 'iconoir-react' import { useAuth } from 'client/features/Auth' -import { useFetchAll } from 'client/hooks' -import { - useUserApi, - useImageApi, - useVNetworkApi, - useDatastoreApi, -} from 'client/features/One' -import * as Widgets from 'client/components/Widgets' +import { useGetUsersQuery } from 'client/features/OneApi/user' +import { useGetGroupsQuery } from 'client/features/OneApi/group' +import { useGetImagesQuery } from 'client/features/OneApi/image' +import { useGetVNetworksQuery } from 'client/features/OneApi/network' +import NumberEasing from 'client/components/NumberEasing' +import WavesCard from 'client/components/Cards/WavesCard' import { stringToBoolean } from 'client/models/Helper' +import { T } from 'client/constants' -/** @returns {JSXElementConstructor} Sunstone dashboard container */ +/** @returns {ReactElement} Sunstone dashboard container */ function SunstoneDashboard() { - const { status, fetchRequestAll, STATUS } = useFetchAll() - const { INIT, PENDING } = STATUS - - const { getUsers } = useUserApi() - const { getImages } = useImageApi() - const { getVNetworks } = useVNetworkApi() - const { getDatastores } = useDatastoreApi() - const { settings: { disableanimations } = {} } = useAuth() - useEffect(() => { - fetchRequestAll([getUsers(), getImages(), getVNetworks(), getDatastores()]) - }, []) - return ( - - - - + + + + + ) } +const ResourceWidget = memo(({ query, ...props }) => { + const { data, isLoading } = query() + const total = `${data?.length ?? 0}` + + return ( + + + ) : ( + + ) + } + {...props} + /> + + ) +}) + +ResourceWidget.displayName = 'ResourceWidget' + +ResourceWidget.propTypes = { + query: PropTypes.func, + text: PropTypes.string, + bgColor: PropTypes.string, + icon: PropTypes.any, +} + export default SunstoneDashboard diff --git a/src/fireedge/src/client/containers/Datastores/index.js b/src/fireedge/src/client/containers/Datastores/index.js index 018022cb66..975fbe5c4b 100644 --- a/src/fireedge/src/client/containers/Datastores/index.js +++ b/src/fireedge/src/client/containers/Datastores/index.js @@ -14,23 +14,52 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ - -import { Container, Box } from '@mui/material' +import { useState } from 'react' +import { Container, Stack, Chip } from '@mui/material' import { DatastoresTable } from 'client/components/Tables' +import DatastoreTabs from 'client/components/Tabs/Datastore' +import SplitPane from 'client/components/SplitPane' +import MultipleTags from 'client/components/MultipleTags' function Datastores() { + const [selectedRows, onSelectedRowsChange] = useState(() => []) + return ( - - - + + + + + {selectedRows?.length > 0 && ( + + {selectedRows?.length === 1 ? ( + + ) : ( + + ( + toggleRowSelected(false)} + /> + ) + )} + /> + + )} + + )} + + ) } diff --git a/src/fireedge/src/client/containers/Groups/index.js b/src/fireedge/src/client/containers/Groups/index.js index f330170379..4311f0252d 100644 --- a/src/fireedge/src/client/containers/Groups/index.js +++ b/src/fireedge/src/client/containers/Groups/index.js @@ -14,23 +14,52 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ - -import { Container, Box } from '@mui/material' +import { useState } from 'react' +import { Container, Stack, Chip } from '@mui/material' import { GroupsTable } from 'client/components/Tables' +import GroupTabs from 'client/components/Tabs/Group' +import SplitPane from 'client/components/SplitPane' +import MultipleTags from 'client/components/MultipleTags' function Groups() { + const [selectedRows, onSelectedRowsChange] = useState(() => []) + return ( - - - + + + + + {selectedRows?.length > 0 && ( + + {selectedRows?.length === 1 ? ( + + ) : ( + + ( + toggleRowSelected(false)} + /> + ) + )} + /> + + )} + + )} + + ) } diff --git a/src/fireedge/src/client/containers/Images/index.js b/src/fireedge/src/client/containers/Images/index.js index df41ce6b3e..552a92c677 100644 --- a/src/fireedge/src/client/containers/Images/index.js +++ b/src/fireedge/src/client/containers/Images/index.js @@ -18,7 +18,7 @@ import { useState } from 'react' import { Container, Stack, Chip } from '@mui/material' import { ImagesTable } from 'client/components/Tables' -import Detail from 'client/components/Tables/Images/detail' +import ImageTabs from 'client/components/Tabs/Image' import SplitPane from 'client/components/SplitPane' import MultipleTags from 'client/components/MultipleTags' @@ -33,7 +33,7 @@ function Images() { {selectedRows?.length > 0 && ( {selectedRows?.length === 1 ? ( - + ) : ( { const { user, groups } = useAuth() diff --git a/src/fireedge/src/client/containers/MarketplaceApps/Create.js b/src/fireedge/src/client/containers/MarketplaceApps/Create.js index af954d2875..4f06dea3df 100644 --- a/src/fireedge/src/client/containers/MarketplaceApps/Create.js +++ b/src/fireedge/src/client/containers/MarketplaceApps/Create.js @@ -13,21 +13,23 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { useMemo, JSXElementConstructor } from 'react' +import { useMemo, ReactElement } from 'react' import { useHistory, useLocation } from 'react-router' import { Container } from '@mui/material' import { useGeneralApi } from 'client/features/General' -import { useMarketplaceAppApi } from 'client/features/One' +import { + useAllocateAppMutation, + useImportAppMutation, +} from 'client/features/OneApi/marketplaceApp' import { CreateForm } from 'client/components/Forms/MarketplaceApp' import { jsonToXml } from 'client/models/Helper' -import { isDevelopment } from 'client/utils' import { RESOURCE_NAMES } from 'client/constants' /** * Displays the creation or modification form to a Marketplace App. * - * @returns {JSXElementConstructor} Marketplace App form + * @returns {ReactElement} Marketplace App form */ function CreateMarketplaceApp() { const history = useHistory() @@ -35,7 +37,8 @@ function CreateMarketplaceApp() { const initialValues = useMemo(() => ({ type: resourceName, id: ID }), []) const { enqueueSuccess } = useGeneralApi() - const { create, importVm, importVmTemplate } = useMarketplaceAppApi() + const [create] = useAllocateAppMutation() + const [importApp] = useImportAppMutation() const onSubmit = async ({ type, ...formData }) => { try { @@ -44,30 +47,22 @@ function CreateMarketplaceApp() { const { id: imageId, marketId, name, image } = formData const xml = jsonToXml({ ORIGIN_ID: imageId, NAME: name, ...image }) - return await create(marketId, xml) - }, - [RESOURCE_NAMES.VM]: async () => { - const { id: vmId, ...data } = formData - - return await importVm(vmId, data) - }, - [RESOURCE_NAMES.VM_TEMPLATE]: async () => { - const { id: templateId, ...data } = formData - - return await importVmTemplate(templateId, data) + return await create({ id: marketId, template: xml }) }, + [RESOURCE_NAMES.VM]: async () => + await importApp({ resource: 'vm', ...formData }), + [RESOURCE_NAMES.VM_TEMPLATE]: async () => + await importApp({ resource: 'vm-template', ...formData }), }[String(type).toLowerCase()] - const response = await createApp?.() + const response = await createApp?.()?.unwrap?.() response && enqueueSuccess(`Marketplace App created: ${response}`) history.goBack() - } catch (err) { - isDevelopment() && console.error(err) - } + } catch {} } return ( - + ) diff --git a/src/fireedge/src/client/containers/Marketplaces/index.js b/src/fireedge/src/client/containers/Marketplaces/index.js index c1ea8a2178..695a3443ce 100644 --- a/src/fireedge/src/client/containers/Marketplaces/index.js +++ b/src/fireedge/src/client/containers/Marketplaces/index.js @@ -14,23 +14,52 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ - -import { Container, Box } from '@mui/material' +import { useState } from 'react' +import { Container, Stack, Chip } from '@mui/material' import { MarketplacesTable } from 'client/components/Tables' +import MarketplaceTabs from 'client/components/Tabs/Marketplace' +import SplitPane from 'client/components/SplitPane' +import MultipleTags from 'client/components/MultipleTags' function Marketplaces() { + const [selectedRows, onSelectedRowsChange] = useState(() => []) + return ( - - - + + + + + {selectedRows?.length > 0 && ( + + {selectedRows?.length === 1 ? ( + + ) : ( + + ( + toggleRowSelected(false)} + /> + ) + )} + /> + + )} + + )} + + ) } diff --git a/src/fireedge/src/client/containers/Providers/Create.js b/src/fireedge/src/client/containers/Providers/Create.js index fec743bf99..1f2c805a32 100644 --- a/src/fireedge/src/client/containers/Providers/Create.js +++ b/src/fireedge/src/client/containers/Providers/Create.js @@ -17,26 +17,30 @@ import { useParams, useHistory } from 'react-router' import { Container } from '@mui/material' -import { useAuth } from 'client/features/Auth' import { useGeneralApi } from 'client/features/General' -import { useProviderApi } from 'client/features/One' +import { + useGetProviderConfigQuery, + useCreateProviderMutation, + useUpdateProviderMutation, +} from 'client/features/OneApi/provider' + import { CreateForm } from 'client/components/Forms/Provider' import { isValidProviderTemplate } from 'client/models/ProviderTemplate' import { PATH } from 'client/apps/provision/routes' -import { isDevelopment } from 'client/utils' function ProviderCreateForm() { const history = useHistory() const { id } = useParams() - - const { providerConfig } = useAuth() const { enqueueSuccess, enqueueError } = useGeneralApi() - const { createProvider, updateProvider } = useProviderApi() + + const { data: providerConfig } = useGetProviderConfigQuery() + const [createProvider] = useCreateProviderMutation() + const [updateProvider] = useUpdateProviderMutation() const onSubmit = async (formData) => { try { if (id !== undefined) { - await updateProvider(id, formData) + await updateProvider({ id, data: formData }) enqueueSuccess(`Provider updated - ID: ${id}`) } else { if (!isValidProviderTemplate(formData, providerConfig)) { @@ -46,18 +50,16 @@ function ProviderCreateForm() { history.push(PATH.PROVIDERS.LIST) } - const responseId = await createProvider(formData) + const responseId = await createProvider({ data: formData }).unwrap() enqueueSuccess(`Provider created - ID: ${responseId}`) } history.push(PATH.PROVIDERS.LIST) - } catch (err) { - isDevelopment() && console.error(err) - } + } catch {} } return ( - + ) diff --git a/src/fireedge/src/client/containers/Providers/Sections/info.js b/src/fireedge/src/client/containers/Providers/Sections/info.js index 486cbc1b3b..44b29e5451 100644 --- a/src/fireedge/src/client/containers/Providers/Sections/info.js +++ b/src/fireedge/src/client/containers/Providers/Sections/info.js @@ -24,25 +24,25 @@ import { EyeEmpty as EyeIcon, } from 'iconoir-react' -import { useFetch } from 'client/hooks' -import { useProviderApi } from 'client/features/One' +import { + useLazyGetProviderConnectionQuery, + useGetProviderQuery, +} from 'client/features/OneApi/provider' import { SubmitButton } from 'client/components/FormControl' import { Tr } from 'client/components/HOC' import { T } from 'client/constants' import useStyles from 'client/containers/Providers/Sections/styles' -const Info = memo(({ fetchProps }) => { +const Info = memo(({ id }) => { const classes = useStyles() - const { getProviderConnection } = useProviderApi() + const [ + getConnection, + { data: decryptConnection, isLoading: noConnectionYet }, + ] = useLazyGetProviderConnectionQuery() + const { data: provider } = useGetProviderQuery(id) - const { - data: showConnection, - fetchRequest, - loading, - } = useFetch(getProviderConnection) - - const { ID, NAME, GNAME, UNAME, PERMISSIONS, TEMPLATE } = fetchProps?.data + const { NAME, GNAME, UNAME, PERMISSIONS, TEMPLATE } = provider const { connection, description, @@ -66,7 +66,7 @@ const Info = memo(({ fetchProps }) => { {'ID'} - {ID} + {id} {Tr(T.Name)} @@ -93,13 +93,13 @@ const Info = memo(({ fetchProps }) => { {Tr(T.Credentials)} - {!showConnection && ( + {!decryptConnection && ( } - onClick={() => fetchRequest(ID)} - isSubmitting={loading} + onClick={async () => await getConnection(id)} + isSubmitting={noConnectionYet} /> )} @@ -111,7 +111,7 @@ const Info = memo(({ fetchProps }) => { {key} - {showConnection?.[key] ?? value} + {decryptConnection?.[key] ?? value} ) @@ -171,18 +171,7 @@ const Info = memo(({ fetchProps }) => { ) }) -Info.propTypes = { - fetchProps: PropTypes.shape({ - data: PropTypes.object.isRequired, - }).isRequired, -} - -Info.defaultProps = { - fetchProps: { - data: {}, - }, -} - +Info.propTypes = { id: PropTypes.string.isRequired } Info.displayName = 'Info' export default Info diff --git a/src/fireedge/src/client/containers/Providers/index.js b/src/fireedge/src/client/containers/Providers/index.js index 02beabb595..154ab7c0d6 100644 --- a/src/fireedge/src/client/containers/Providers/index.js +++ b/src/fireedge/src/client/containers/Providers/index.js @@ -13,121 +13,178 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useState, useEffect } from 'react' +import { memo, ReactElement, useEffect } from 'react' +import PropTypes from 'prop-types' import { useHistory, generatePath } from 'react-router-dom' -import { Container, Box } from '@mui/material' +import { Container, Box, Backdrop, CircularProgress } from '@mui/material' import { Trash as DeleteIcon, Settings as EditIcon } from 'iconoir-react' -import { PATH } from 'client/apps/provision/routes' -import { useProvider, useProviderApi } from 'client/features/One' +import { + useGetProviderConfigQuery, + useGetProvidersQuery, + useDeleteProviderMutation, + useGetProviderQuery, +} from 'client/features/OneApi/provider' import { useGeneralApi } from 'client/features/General' -import { useFetch, useSearch } from 'client/hooks' -import { useAuth } from 'client/features/Auth' +import { useSearch, useDialog } from 'client/hooks' import { ListHeader, ListCards } from 'client/components/List' import AlertError from 'client/components/Alerts/Error' import { ProvisionCard } from 'client/components/Cards' -import { DialogRequest } from 'client/components/Dialogs' +import { DialogConfirmation } from 'client/components/Dialogs' +import { Translate } from 'client/components/HOC' import Information from 'client/containers/Providers/Sections/info' +import { PATH } from 'client/apps/provision/routes' import { T } from 'client/constants' +/** + * Renders a list of available providers. + * + * @returns {ReactElement} List of providers + */ function Providers() { const history = useHistory() - const [showDialog, setShowDialog] = useState(false) + const { display, show, hide, values: dialogProps } = useDialog() - const { providerConfig } = useAuth() - const providers = useProvider() - const { getProviders, getProvider, deleteProvider } = useProviderApi() const { enqueueSuccess } = useGeneralApi() + const { data: providerConfig } = useGetProviderConfigQuery() + const [deleteProvider, { isLoading: isDeleting }] = + useDeleteProviderMutation() - const { error, fetchRequest, loading, reloading } = useFetch(getProviders) + const { + refetch, + data: providers = [], + isFetching, + error, + } = useGetProvidersQuery() const { result, handleChange } = useSearch({ list: providers, listOptions: { shouldSort: true, keys: ['ID', 'NAME'] }, }) - useEffect(() => { - fetchRequest() - }, []) - - const handleCancel = () => setShowDialog(false) + const handleDelete = async (id) => { + try { + hide() + await deleteProvider({ id }) + enqueueSuccess(`Provider deleted - ID: ${id}`) + } catch {} + } return ( - - fetchRequest(undefined, { reload: true }), - isSubmitting: Boolean(loading || reloading), - }} - addButtonProps={{ - 'data-cy': 'create-provider', - onClick: () => history.push(PATH.PROVIDERS.CREATE), - }} - searchProps={{ handleChange }} - /> - - {error ? ( - {T.CannotConnectOneProvision} - ) : ( - ({ - image: providerConfig[TEMPLATE?.PLAIN?.provider]?.image, - isProvider: true, - handleClick: () => - setShowDialog({ - id: ID, - title: `#${ID} ${NAME}`, - }), - actions: [ - { - handleClick: () => - history.push(generatePath(PATH.PROVIDERS.EDIT, { id: ID })), - icon: , - cy: 'provider-edit', - }, - { - handleClick: () => - setShowDialog({ - id: ID, - title: `DELETE | #${ID} ${NAME}`, - handleAccept: () => { - setShowDialog(false) - - return deleteProvider(ID) - .then(() => - enqueueSuccess(`Provider deleted - ID: ${ID}`) - ) - .then(() => fetchRequest(undefined, { reload: true })) - }, - }), - icon: , - color: 'error', - cy: 'provider-delete', - }, - ], - })} - /> - )} - - {showDialog !== false && ( - getProvider(showDialog.id)} - dialogProps={{ fixedWidth: true, handleCancel, ...showDialog }} - > - {(fetchProps) => } - + <> + + refetch(), + isSubmitting: isFetching, + }} + addButtonProps={{ + 'data-cy': 'create-provider', + onClick: () => history.push(PATH.PROVIDERS.CREATE), + }} + searchProps={{ handleChange }} + /> + + {error ? ( + {T.CannotConnectOneProvision} + ) : ( + ({ + image: providerConfig[TEMPLATE?.PLAIN?.provider]?.image, + isProvider: true, + handleClick: () => show({ id: ID, title: `#${ID} ${NAME}` }), + actions: [ + { + handleClick: () => + history.push( + generatePath(PATH.PROVIDERS.EDIT, { id: ID }) + ), + icon: , + cy: 'provider-edit', + }, + { + handleClick: () => + show({ + id: ID, + title: ( + + ), + handleAccept: () => handleDelete(ID), + }), + icon: , + isSubmitting: isDeleting, + color: 'error', + cy: 'provider-delete', + }, + ], + })} + /> + )} + + + {display && dialogProps?.id && ( + )} - + ) } +const DialogProvider = memo( + ({ id, hide, dialogProps }) => { + const { + currentData: providerDetail, + isLoading: providerIsLoading, + error: providerError, + } = useGetProviderQuery(id) + + useEffect(() => { + providerError && hide() + }, [providerError]) + + return providerDetail?.ID !== id || providerIsLoading ? ( + theme.zIndex.drawer + 1, + color: (theme) => theme.palette.common.white, + }} + > + + + ) : ( + + + + ) + }, + (prev, next) => prev.id === next.id +) + +DialogProvider.propTypes = { + id: PropTypes.string, + hide: PropTypes.func, + dialogProps: PropTypes.object, +} + +DialogProvider.displayName = 'DialogProvider' + export default Providers diff --git a/src/fireedge/src/client/containers/Provisions/Create.js b/src/fireedge/src/client/containers/Provisions/Create.js index 147657dc43..35020d72c6 100644 --- a/src/fireedge/src/client/containers/Provisions/Create.js +++ b/src/fireedge/src/client/containers/Provisions/Create.js @@ -14,7 +14,7 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ -import { useEffect, useState, memo } from 'react' +import { useState, memo } from 'react' import { Redirect, useHistory } from 'react-router' import { NavArrowLeft as ArrowBackIcon } from 'iconoir-react' @@ -26,14 +26,14 @@ import { } from '@mui/material' import makeStyles from '@mui/styles/makeStyles' -import { useFetch, useSocket } from 'client/hooks' +import { useSocket } from 'client/hooks' import { useGeneralApi } from 'client/features/General' -import { useProviderApi, useProvisionApi } from 'client/features/One' +import { useCreateProvisionMutation } from 'client/features/OneApi/provision' +import { useGetProvidersQuery } from 'client/features/OneApi/provider' import DebugLog from 'client/components/DebugLog' import { CreateForm } from 'client/components/Forms/Provision' import { PATH } from 'client/apps/provision/routes' import { Translate } from 'client/components/HOC' -import { isDevelopment } from 'client/utils' import { T } from 'client/constants' const useStyles = makeStyles({ @@ -55,25 +55,18 @@ function ProvisionCreateForm() { const { getProvisionSocket: socket } = useSocket() const { enqueueInfo } = useGeneralApi() - const { createProvision } = useProvisionApi() - const { getProviders } = useProviderApi() - const { data, fetchRequest, loading, error } = useFetch(getProviders) + const [createProvision] = useCreateProvisionMutation() + const { data, isLoading, error } = useGetProvidersQuery() const onSubmit = async (formData) => { try { - const response = await createProvision(formData) + const response = await createProvision({ data: formData }).unwrap() enqueueInfo('Creating provision') response && setUuid(response) - } catch (err) { - isDevelopment() && console.error(err) - } + } catch {} } - useEffect(() => { - fetchRequest() - }, []) - if (uuid) { return }} /> } @@ -82,7 +75,7 @@ function ProvisionCreateForm() { return } - return !data || loading ? ( + return !data || isLoading ? ( ) : ( diff --git a/src/fireedge/src/client/containers/Provisions/DialogInfo/datastores.js b/src/fireedge/src/client/containers/Provisions/DialogInfo/datastores.js index 57657d0ed0..992c301aa2 100644 --- a/src/fireedge/src/client/containers/Provisions/DialogInfo/datastores.js +++ b/src/fireedge/src/client/containers/Provisions/DialogInfo/datastores.js @@ -13,60 +13,74 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useEffect } from 'react' +import { memo } from 'react' import PropTypes from 'prop-types' import { Trash as DeleteIcon } from 'iconoir-react' -import { useFetchAll } from 'client/hooks' -import { useDatastoreApi, useProvisionApi } from 'client/features/One' +import { + useGetProvisionQuery, + useGetResourceQuery, + useRemoveResourceMutation, +} from 'client/features/OneApi/provision' import { useGeneralApi } from 'client/features/General' -import { ListCards } from 'client/components/List' + +import { DatastoresTable } from 'client/components/Tables' import { DatastoreCard } from 'client/components/Cards' +import { SubmitButton } from 'client/components/FormControl' const Datastores = memo( - ({ hidden, data, reloading, refetchProvision, disableAllActions }) => { - const { datastores = [] } = data?.TEMPLATE?.BODY?.provision?.infrastructure - + ({ id }) => { const { enqueueSuccess } = useGeneralApi() - const { deleteDatastore } = useProvisionApi() - const { getDatastore } = useDatastoreApi() - const { data: list, fetchRequestAll, loading } = useFetchAll() - const fetchDatastores = () => - fetchRequestAll(datastores?.map(({ id }) => getDatastore(id))) + const [removeResource, { isLoading: loadingRemove }] = + useRemoveResourceMutation() + const { data } = useGetProvisionQuery(id) - useEffect(() => { - !hidden && !list && fetchDatastores() - }, [hidden]) - - useEffect(() => { - !reloading && !loading && fetchDatastores() - }, [reloading]) + const provisionDatastores = + data?.TEMPLATE?.BODY?.provision?.infrastructure?.datastores?.map( + (datastore) => +datastore.id + ) ?? [] return ( - - !disableAllActions && { - actions: [ - { - handleClick: () => - deleteDatastore(ID) - .then(refetchProvision) - .then(() => - enqueueSuccess(`Datastore deleted - ID: ${ID}`) - ), - icon: , - cy: `provision-datastore-delete-${ID}`, - }, - ], - } + + useGetResourceQuery( + { resource: 'datastore' }, + { + selectFromResult: ({ data: result = [], ...rest }) => ({ + data: result?.filter((datastore) => + provisionDatastores.includes(+datastore.ID) + ), + ...rest, + }), + } + ) } - displayEmpty - breakpoints={{ xs: 12, md: 6 }} + RowComponent={({ original: datastore, handleClick: _, ...props }) => ( + } + isSubmitting={loadingRemove} + onClick={async () => { + removeResource({ + provision: id, + id: datastore.ID, + resource: 'datastore', + }) + enqueueSuccess(`Datastore deleted - ID: ${datastore.ID}`) + }} + /> + } + /> + )} /> ) }, @@ -74,22 +88,7 @@ const Datastores = memo( prev.hidden === next.hidden && prev.reloading === next.reloading ) -Datastores.propTypes = { - data: PropTypes.object.isRequired, - hidden: PropTypes.bool, - refetchProvision: PropTypes.func, - reloading: PropTypes.bool, - disableAllActions: PropTypes.bool, -} - -Datastores.defaultProps = { - data: {}, - hidden: false, - refetchProvision: () => undefined, - reloading: false, - disableAllActions: false, -} - +Datastores.propTypes = { id: PropTypes.string.isRequired } Datastores.displayName = 'Datastores' export default Datastores diff --git a/src/fireedge/src/client/containers/Provisions/DialogInfo/hosts.js b/src/fireedge/src/client/containers/Provisions/DialogInfo/hosts.js index d5a90ad692..2b79e5341c 100644 --- a/src/fireedge/src/client/containers/Provisions/DialogInfo/hosts.js +++ b/src/fireedge/src/client/containers/Provisions/DialogInfo/hosts.js @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useEffect, useState } from 'react' +import { memo, useState } from 'react' import PropTypes from 'prop-types' import { @@ -23,120 +23,120 @@ import { } from 'iconoir-react' import { Stack, TextField } from '@mui/material' -import { useFetch, useFetchAll } from 'client/hooks' -import { useHostApi, useProvisionApi } from 'client/features/One' import { useGeneralApi } from 'client/features/General' -import { SubmitButton } from 'client/components/FormControl' -import { ListCards } from 'client/components/List' +import { + useGetProvisionQuery, + useAddHostToProvisionMutation, + useConfigureHostMutation, + useRemoveResourceMutation, + useGetResourceQuery, +} from 'client/features/OneApi/provision' + +import { HostsTable } from 'client/components/Tables' import { HostCard } from 'client/components/Cards' +import { SubmitButton } from 'client/components/FormControl' import { Translate } from 'client/components/HOC' import { T } from 'client/constants' -const Hosts = memo( - ({ hidden, data, reloading, refetchProvision, disableAllActions }) => { - const [amount, setAmount] = useState(() => 1) - const { hosts = [] } = data?.TEMPLATE?.BODY?.provision?.infrastructure +const Hosts = memo(({ id }) => { + const [amount, setAmount] = useState(() => 1) + const { enqueueSuccess, enqueueInfo } = useGeneralApi() - const { enqueueSuccess, enqueueInfo } = useGeneralApi() - const { configureHost, deleteHost, addHost } = useProvisionApi() - const { getHost } = useHostApi() + const [addHost, { isLoading: loadingAddHost }] = + useAddHostToProvisionMutation() + const [configureHost, { isLoading: loadingConfigure }] = + useConfigureHostMutation() + const [removeResource, { isLoading: loadingRemove }] = + useRemoveResourceMutation() + const { data = {} } = useGetProvisionQuery(id) - const { fetchRequest, loading: loadingAddHost } = useFetch( - async (payload) => { - await addHost(data?.ID, payload) - await refetchProvision() - enqueueSuccess(`Adding hosts ${amount}x`) - } - ) + const provisionHosts = + data?.TEMPLATE?.BODY?.provision?.infrastructure?.hosts?.map( + (host) => +host.id + ) ?? [] - const { data: list, fetchRequestAll, loading } = useFetchAll() - const fetchHosts = () => - fetchRequestAll(hosts?.map(({ id }) => getHost(id))) - - useEffect(() => { - !hidden && !list && fetchHosts() - }, [hidden]) - - useEffect(() => { - !reloading && !loading && fetchHosts() - }, [reloading]) - - return ( - <> - - { - const newAmount = event.target.value - ;+newAmount > 0 && setAmount(newAmount) - }} - value={amount} - /> - - } - label={} - isSubmitting={loadingAddHost} - onClick={() => fetchRequest(amount)} - /> - - - - !disableAllActions && { - actions: [ - { - handleClick: () => - configureHost(ID) - .then(() => enqueueInfo(`Configuring host - ID: ${ID}`)) - .then(refetchProvision), - icon: , - cy: `provision-host-configure-${ID}`, - }, - { - handleClick: () => - deleteHost(ID) - .then(refetchProvision) - .then(() => enqueueSuccess(`Host deleted - ID: ${ID}`)), - icon: , - cy: `provision-host-delete-${ID}`, - }, - ], - } - } - displayEmpty - breakpoints={{ xs: 12, md: 6 }} + return ( + <> + + { + const newAmount = event.target.value + ;+newAmount > 0 && setAmount(newAmount) + }} + value={amount} /> - - ) - }, - (prev, next) => - prev.hidden === next.hidden && prev.reloading === next.reloading -) - -Hosts.propTypes = { - data: PropTypes.object.isRequired, - hidden: PropTypes.bool, - refetchProvision: PropTypes.func, - reloading: PropTypes.bool, - disableAllActions: PropTypes.bool, -} - -Hosts.defaultProps = { - data: {}, - hidden: false, - refetchProvision: () => undefined, - reloading: false, - disableAllActions: false, -} + + } + label={} + isSubmitting={loadingAddHost} + onClick={async () => { + addHost({ id, amount }) + enqueueSuccess(`Host added ${amount}x`) + }} + /> + + + + useGetResourceQuery( + { resource: 'host' }, + { + selectFromResult: ({ data: result = [], ...rest }) => ({ + data: result?.filter((host) => + provisionHosts.includes(+host.ID) + ), + ...rest, + }), + } + ) + } + RowComponent={({ original: host, handleClick: _, ...props }) => ( + + } + isSubmitting={loadingConfigure} + onClick={async () => { + configureHost({ provision: id, id: host.ID }) + enqueueInfo(`Configuring host - ID: ${host.ID}`) + }} + /> + } + isSubmitting={loadingRemove} + onClick={async () => { + removeResource({ + provision: id, + id: host.ID, + resource: 'host', + }) + enqueueSuccess(`Host deleted - ID: ${host.ID}`) + }} + /> + + } + /> + )} + /> + + ) +}) +Hosts.propTypes = { id: PropTypes.string.isRequired } Hosts.displayName = 'Hosts' export default Hosts diff --git a/src/fireedge/src/client/containers/Provisions/DialogInfo/index.js b/src/fireedge/src/client/containers/Provisions/DialogInfo/index.js index a896484358..ea72a80b73 100644 --- a/src/fireedge/src/client/containers/Provisions/DialogInfo/index.js +++ b/src/fireedge/src/client/containers/Provisions/DialogInfo/index.js @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useState, useMemo } from 'react' +import { useMemo, ReactElement } from 'react' import PropTypes from 'prop-types' - -import { AppBar, Tabs, Tab, Box } from '@mui/material' import { InfoEmpty as InfoIcon, HardDrive as HostIcon, @@ -26,94 +23,61 @@ import { Page as LogIcon, } from 'iconoir-react' +import Tabs from 'client/components/Tabs' import InfoTab from 'client/containers/Provisions/DialogInfo/info' import DatastoresTab from 'client/containers/Provisions/DialogInfo/datastores' import NetworksTab from 'client/containers/Provisions/DialogInfo/networks' import HostsTab from 'client/containers/Provisions/DialogInfo/hosts' import LogTab from 'client/containers/Provisions/DialogInfo/log' +import { T } from 'client/constants' -const TABS = [ - { name: 'info', icon: InfoIcon, content: InfoTab }, - { name: 'datastores', icon: DatastoreIcon, content: DatastoresTab }, - { name: 'networks', icon: NetworkIcon, content: NetworksTab }, - { name: 'hosts', icon: HostIcon, content: HostsTab }, - { name: 'log', icon: LogIcon, content: LogTab }, -] - -const DialogInfo = ({ disableAllActions, fetchProps }) => { - const [tabSelected, setTab] = useState(0) - const { data, fetchRequest, reloading } = fetchProps - - const renderTabs = useMemo( - () => ( - - setTab(tab)} - > - {TABS.map(({ name, icon: Icon }, idx) => ( - } - value={idx} - label={String(name).toUpperCase()} - /> - ))} - - - ), - [tabSelected] +/** + * Renders information about provision: infrastructures, log, etc. + * + * @param {object} props - Props + * @param {string} props.id - Provision id + * @returns {ReactElement} - Provision id + */ +const DialogInfo = ({ id }) => { + const tabsAvailable = useMemo( + () => [ + { + name: 'info', + label: T.Info, + icon: InfoIcon, + renderContent: () => , + }, + { + name: 'datastores', + label: T.Datastores, + icon: DatastoreIcon, + renderContent: () => , + }, + { + name: 'networks', + label: T.Networks, + icon: NetworkIcon, + renderContent: () => , + }, + { + name: 'hosts', + label: T.Hosts, + icon: HostIcon, + renderContent: () => , + }, + { + name: 'log', + label: T.Log, + icon: LogIcon, + renderContent: () => , + }, + ], + [] ) - return ( - <> - {renderTabs} - {useMemo( - () => - TABS.map(({ name, content: Content }, idx) => ( - - )), - [tabSelected, reloading] - )} - - ) + return } -DialogInfo.propTypes = { - disableAllActions: PropTypes.bool, - fetchProps: PropTypes.shape({ - data: PropTypes.object.isRequired, - fetchRequest: PropTypes.func, - reloading: PropTypes.bool, - }).isRequired, -} - -DialogInfo.defaultProps = { - disableAllActions: false, - fetchProps: { - data: {}, - fetchRequest: undefined, - reloading: false, - }, -} +DialogInfo.propTypes = { id: PropTypes.string.isRequired } export default DialogInfo diff --git a/src/fireedge/src/client/containers/Provisions/DialogInfo/info.js b/src/fireedge/src/client/containers/Provisions/DialogInfo/info.js index 6f144a6bcf..df6cb239e3 100644 --- a/src/fireedge/src/client/containers/Provisions/DialogInfo/info.js +++ b/src/fireedge/src/client/containers/Provisions/DialogInfo/info.js @@ -20,13 +20,16 @@ import clsx from 'clsx' import { List, ListItem, Typography, Grid, Paper, Divider } from '@mui/material' import { Check as CheckIcon, Square as BlankSquareIcon } from 'iconoir-react' +import { useGetProvisionQuery } from 'client/features/OneApi/provision' import useStyles from 'client/containers/Provisions/DialogInfo/styles' import { StatusChip } from 'client/components/Status' import { Tr } from 'client/components/HOC' import { T, PROVISIONS_STATES } from 'client/constants' -const Info = memo(({ data = {} }) => { +const Info = memo(({ id }) => { const classes = useStyles() + + const { data = {} } = useGetProvisionQuery(id) const { ID, GNAME, UNAME, PERMISSIONS, TEMPLATE } = data const { state, @@ -140,14 +143,7 @@ const Info = memo(({ data = {} }) => { ) }) -Info.propTypes = { - data: PropTypes.object.isRequired, -} - -Info.defaultProps = { - data: undefined, -} - +Info.propTypes = { id: PropTypes.string.isRequired } Info.displayName = 'Info' export default Info diff --git a/src/fireedge/src/client/containers/Provisions/DialogInfo/log.js b/src/fireedge/src/client/containers/Provisions/DialogInfo/log.js index af2f84ff31..76be13b5df 100644 --- a/src/fireedge/src/client/containers/Provisions/DialogInfo/log.js +++ b/src/fireedge/src/client/containers/Provisions/DialogInfo/log.js @@ -13,70 +13,42 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useEffect, useMemo } from 'react' +import { memo, useMemo } from 'react' import PropTypes from 'prop-types' import { LinearProgress } from '@mui/material' -import { useFetch, useSocket } from 'client/hooks' -import { useProvisionApi } from 'client/features/One' +import { useSocket } from 'client/hooks' +import { useGetProvisionLogQuery } from 'client/features/OneApi/provision' import DebugLog, { LogUtils } from 'client/components/DebugLog' -const Log = memo( - ({ hidden, data: { ID } }) => { - const { getProvisionSocket } = useSocket() - const { getProvisionLog } = useProvisionApi() +const Log = memo(({ id }) => { + const { getProvisionSocket } = useSocket() + const { data, isLoading } = useGetProvisionLogQuery(id) + const { uuid = id, log } = data ?? {} - const { - data: { uuid = ID, log } = {}, - fetchRequest, - loading, - } = useFetch(getProvisionLog) + const parsedLog = useMemo( + () => + log + ?.map((entry) => { + try { + return JSON.parse(entry) + } catch { + return entry + } + }) + ?.reduce(LogUtils.concatNewMessageToLog, {}), + [isLoading] + ) - useEffect(() => { - !log && !hidden && fetchRequest(ID) - }, [hidden]) - - const parsedLog = useMemo( - () => - log - ?.map((entry) => { - try { - return JSON.parse(entry) - } catch { - return entry - } - }) - ?.reduce(LogUtils.concatNewMessageToLog, {}), - [loading] - ) - - return loading ? ( - - ) : ( - - ) - }, - (prev, next) => - prev.hidden === next.hidden && prev.reloading === next.reloading -) - -Log.propTypes = { - data: PropTypes.object.isRequired, - hidden: PropTypes.bool, - fetchRequest: PropTypes.func, -} - -Log.defaultProps = { - data: {}, - hidden: false, - fetchRequest: () => undefined, -} + return isLoading ? ( + + ) : ( + + ) +}) +Log.propTypes = { id: PropTypes.string.isRequired } Log.displayName = 'Log' export default Log diff --git a/src/fireedge/src/client/containers/Provisions/DialogInfo/networks.js b/src/fireedge/src/client/containers/Provisions/DialogInfo/networks.js index 416e661e37..6b1205235d 100644 --- a/src/fireedge/src/client/containers/Provisions/DialogInfo/networks.js +++ b/src/fireedge/src/client/containers/Provisions/DialogInfo/networks.js @@ -13,120 +13,113 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { memo, useEffect, useState } from 'react' +import { memo, useState } from 'react' import PropTypes from 'prop-types' import { Trash as DeleteIcon, AddCircledOutline } from 'iconoir-react' import { Stack, TextField } from '@mui/material' -import { useFetch, useFetchAll } from 'client/hooks' -import { useVNetworkApi, useProvisionApi } from 'client/features/One' import { useGeneralApi } from 'client/features/General' -import { SubmitButton } from 'client/components/FormControl' -import { ListCards } from 'client/components/List' +import { + useGetProvisionQuery, + useAddIpToProvisionMutation, + useRemoveResourceMutation, + useGetResourceQuery, +} from 'client/features/OneApi/provision' + +import { VNetworksTable } from 'client/components/Tables' import { NetworkCard } from 'client/components/Cards' +import { SubmitButton } from 'client/components/FormControl' import { Translate } from 'client/components/HOC' import { T } from 'client/constants' -const Networks = memo( - ({ hidden, data, reloading, refetchProvision, disableAllActions }) => { - const [amount, setAmount] = useState(() => 1) - const { networks = [] } = data?.TEMPLATE?.BODY?.provision?.infrastructure +const Networks = memo(({ id }) => { + const [amount, setAmount] = useState(() => 1) + const { enqueueSuccess } = useGeneralApi() - const { enqueueSuccess } = useGeneralApi() - const { deleteVNetwork, addIp } = useProvisionApi() - const { getVNetwork } = useVNetworkApi() + const [addIp, { isLoading: loadingAddIp }] = useAddIpToProvisionMutation() + const [removeResource, { isLoading: loadingRemove }] = + useRemoveResourceMutation() + const { data = {} } = useGetProvisionQuery(id) - const { fetchRequest, loading: loadingAddIp } = useFetch( - async (payload) => { - await addIp(data?.ID, payload) - await refetchProvision() - enqueueSuccess(`IP added ${amount}x`) - } - ) + const provisionNetworks = + data?.TEMPLATE?.BODY?.provision?.infrastructure?.networks?.map( + (network) => +network.id + ) ?? [] - const { data: list, fetchRequestAll, loading } = useFetchAll() - const fetchVNetworks = () => - fetchRequestAll(networks?.map(({ id }) => getVNetwork(id))) - - useEffect(() => { - !hidden && !list && fetchVNetworks() - }, [hidden]) - - useEffect(() => { - !reloading && !loading && fetchVNetworks() - }, [reloading]) - - return ( - <> - - { - const newAmount = event.target.value - ;+newAmount > 0 && setAmount(newAmount) - }} - value={amount} - /> - - } - label={} - sx={{ ml: 1, display: 'flex', alignItems: 'flex-start' }} - isSubmitting={loadingAddIp} - onClick={() => fetchRequest(amount)} - /> - - - - !disableAllActions && { - actions: [ - { - handleClick: () => - deleteVNetwork(ID) - .then(refetchProvision) - .then(() => - enqueueSuccess(`VNetwork deleted - ID: ${ID}`) - ), - icon: , - cy: `provision-vnet-delete-${ID}`, - }, - ], - } - } - displayEmpty - breakpoints={{ xs: 12, md: 6 }} + return ( + <> + + { + const newAmount = event.target.value + ;+newAmount > 0 && setAmount(newAmount) + }} + value={amount} /> - - ) - }, - (prev, next) => - prev.hidden === next.hidden && prev.reloading === next.reloading -) - -Networks.propTypes = { - data: PropTypes.object.isRequired, - hidden: PropTypes.bool, - refetchProvision: PropTypes.func, - reloading: PropTypes.bool, - disableAllActions: PropTypes.bool, -} - -Networks.defaultProps = { - data: {}, - hidden: false, - refetchProvision: () => undefined, - reloading: false, - disableAllActions: false, -} + + } + label={} + sx={{ ml: 1, display: 'flex', alignItems: 'flex-start' }} + isSubmitting={loadingAddIp} + onClick={async () => { + await addIp({ id, amount }) + enqueueSuccess(`IP added ${amount}x`) + }} + /> + + + + useGetResourceQuery( + { resource: 'network' }, + { + selectFromResult: ({ data: result = [], ...rest }) => ({ + data: result?.filter((vnet) => + provisionNetworks.includes(+vnet.ID) + ), + ...rest, + }), + } + ) + } + RowComponent={({ original: vnet, handleClick: _, ...props }) => ( + + } + isSubmitting={loadingRemove} + onClick={async () => { + removeResource({ + provision: id, + id: vnet.ID, + resource: 'network', + }) + enqueueSuccess(`Network deleted - ID: ${vnet.ID}`) + }} + /> + + } + /> + )} + /> + + ) +}) +Networks.propTypes = { id: PropTypes.string.isRequired } Networks.displayName = 'Networks' export default Networks diff --git a/src/fireedge/src/client/containers/Provisions/index.js b/src/fireedge/src/client/containers/Provisions/index.js index 09bf7b4a22..b8539b4524 100644 --- a/src/fireedge/src/client/containers/Provisions/index.js +++ b/src/fireedge/src/client/containers/Provisions/index.js @@ -13,16 +13,19 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ -import { useState, useEffect, createElement } from 'react' +import { ReactElement } from 'react' import { useHistory } from 'react-router-dom' -import { Container, Box } from '@mui/material' +import { Container, Box, Backdrop, CircularProgress } from '@mui/material' import { Trash as DeleteIcon, Settings as EditIcon } from 'iconoir-react' -import { PATH } from 'client/apps/provision/routes' -import { useFetch, useSearch } from 'client/hooks' -import { useProvision, useProvisionApi } from 'client/features/One' +import { + useGetProvisionsQuery, + useLazyGetProvisionQuery, + useConfigureProvisionMutation, + useDeleteProvisionMutation, +} from 'client/features/OneApi/provision' +import { useSearch, useDialog } from 'client/hooks' import { useGeneralApi } from 'client/features/General' import { DeleteForm } from 'client/components/Forms/Provision' @@ -31,127 +34,141 @@ import AlertError from 'client/components/Alerts/Error' import { ProvisionCard } from 'client/components/Cards' import { Translate } from 'client/components/HOC' -import { DialogRequest } from 'client/components/Dialogs' +import { DialogConfirmation } from 'client/components/Dialogs' import DialogInfo from 'client/containers/Provisions/DialogInfo' +import { PATH } from 'client/apps/provision/routes' import { T } from 'client/constants' +/** + * Renders a list of available cluster provisions. + * + * @returns {ReactElement} List of provisions + */ function Provisions() { const history = useHistory() - const [{ content, ...showDialog } = {}, setShowDialog] = useState() - const handleCloseDialog = () => setShowDialog() + const { display, show, hide, values: dialogProps } = useDialog() const { enqueueInfo } = useGeneralApi() - const provisions = useProvision() + const [configureProvision] = useConfigureProvisionMutation() + const [deleteProvision] = useDeleteProvisionMutation() - const { getProvisions, getProvision, configureProvision, deleteProvision } = - useProvisionApi() + const { + refetch, + data: provisions = [], + isFetching, + error, + } = useGetProvisionsQuery() - const { error, fetchRequest, loading, reloading } = useFetch(getProvisions) + const [ + getProvision, + { + currentData: provisionDetail, + isLoading: provisionIsLoading, + error: provisionError, + originalArgs, + }, + ] = useLazyGetProvisionQuery() const { result, handleChange } = useSearch({ list: provisions, listOptions: { shouldSort: true, keys: ['ID', 'NAME'] }, }) - useEffect(() => { - fetchRequest() - }, []) - return ( - - fetchRequest(undefined, { reload: true }), - isSubmitting: Boolean(loading || reloading), - }} - addButtonProps={{ - 'data-cy': 'create-provision', - onClick: () => history.push(PATH.PROVISIONS.CREATE), - }} - searchProps={{ handleChange }} - /> - - {error ? ( - {T.CannotConnectOneProvision} - ) : ( - ({ - handleClick: () => - setShowDialog({ - id: ID, - title: `#${ID} ${NAME}`, - content: (props) => - createElement(DialogInfo, { - ...props, - displayName: 'DialogDetailProvision', - }), - }), - actions: [ - { - handleClick: () => - configureProvision(ID) - .then(() => - enqueueInfo(`Configuring provision - ID: ${ID}`) - ) - .then(() => fetchRequest(undefined, { reload: true })), - icon: , - cy: 'provision-configure', + <> + + refetch(), + isSubmitting: isFetching, + }} + addButtonProps={{ + 'data-cy': 'create-provision', + onClick: () => history.push(PATH.PROVISIONS.CREATE), + }} + searchProps={{ handleChange }} + /> + + {error ? ( + {T.CannotConnectOneProvision} + ) : ( + ({ + handleClick: () => { + getProvision(ID) + show({ id: ID, title: `#${ID} ${NAME}` }) }, - ], - deleteAction: { - buttonProps: { - 'data-cy': 'provision-delete', - icon: , - color: 'error', - }, - options: [ + actions: [ { - dialogProps: { - title: ( - - ), - }, - form: DeleteForm, - onSubmit: async (formData) => { - try { - await deleteProvision(ID, formData) - enqueueInfo(`Deleting provision - ID: ${ID}`) - } finally { - handleCloseDialog() - fetchRequest(undefined, { reload: true }) - } + handleClick: async () => { + await configureProvision({ id: ID }) + enqueueInfo(`Configuring provision - ID: ${ID}`) }, + icon: , + cy: 'provision-configure', }, ], - }, - })} - /> - )} - - {content && ( - getProvision(showDialog.id)} - dialogProps={{ - fixedWidth: true, - fixedHeight: true, - handleCancel: handleCloseDialog, - ...showDialog, - }} - > - {(props) => content(props)} - - )} - + deleteAction: { + buttonProps: { + 'data-cy': 'provision-delete', + icon: , + color: 'error', + }, + options: [ + { + dialogProps: { + title: ( + + ), + }, + form: DeleteForm, + onSubmit: async (formData) => { + try { + await deleteProvision({ id: ID, ...formData }) + enqueueInfo(`Deleting provision - ID: ${ID}`) + } finally { + hide() + } + }, + }, + ], + }, + })} + /> + )} + + + {display && + !provisionError && + (provisionDetail?.ID !== originalArgs || provisionIsLoading ? ( + theme.zIndex.drawer + 1, + color: (theme) => theme.palette.common.white, + }} + > + + + ) : ( + + + + ))} + ) } diff --git a/src/fireedge/src/client/containers/Settings/index.js b/src/fireedge/src/client/containers/Settings/index.js index 4dd9d419cf..6b8c2bb986 100644 --- a/src/fireedge/src/client/containers/Settings/index.js +++ b/src/fireedge/src/client/containers/Settings/index.js @@ -22,7 +22,7 @@ import FormWithSchema from 'client/components/Forms/FormWithSchema' import SubmitButton from 'client/components/FormControl/SubmitButton' import { useAuth, useAuthApi } from 'client/features/Auth' -import { useUserApi } from 'client/features/One' +import { useUpdateUserMutation } from 'client/features/OneApi/user' import { useGeneralApi } from 'client/features/General' import { Translate, Tr } from 'client/components/HOC' import { T } from 'client/constants' @@ -34,7 +34,7 @@ import * as Helper from 'client/models/Helper' const Settings = () => { const { user, settings } = useAuth() const { getAuthUser } = useAuthApi() - const { updateUser } = useUserApi() + const [updateUser] = useUpdateUserMutation() const { enqueueError } = useGeneralApi() const { handleSubmit, setError, reset, formState, ...methods } = useForm({ @@ -46,7 +46,8 @@ const Settings = () => { const onSubmit = async (dataForm) => { try { const template = Helper.jsonToXml({ FIREEDGE: dataForm }) - await updateUser(user.ID, { template }).then(getAuthUser) + await updateUser({ id: user.ID, template }) + getAuthUser() } catch { enqueueError(T.SomethingWrong) } diff --git a/src/fireedge/src/client/containers/TestApi/ResponseForm.js b/src/fireedge/src/client/containers/TestApi/ResponseForm.js index 8a6c1ebdd8..bd5f2b6ec3 100644 --- a/src/fireedge/src/client/containers/TestApi/ResponseForm.js +++ b/src/fireedge/src/client/containers/TestApi/ResponseForm.js @@ -64,7 +64,7 @@ const ResponseForm = ({ color="textPrimary" component="h2" variant="h2" - style={{ padding: '16px 0' }} + sx={{ p: '16px 0' }} > {name || 'Request'} diff --git a/src/fireedge/src/client/containers/Users/index.js b/src/fireedge/src/client/containers/Users/index.js index 6ad7e76724..eb0b0b0ad1 100644 --- a/src/fireedge/src/client/containers/Users/index.js +++ b/src/fireedge/src/client/containers/Users/index.js @@ -14,23 +14,52 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ - -import { Container, Box } from '@mui/material' +import { useState } from 'react' +import { Container, Stack, Chip } from '@mui/material' import { UsersTable } from 'client/components/Tables' +import UserTabs from 'client/components/Tabs/User' +import SplitPane from 'client/components/SplitPane' +import MultipleTags from 'client/components/MultipleTags' function Users() { + const [selectedRows, onSelectedRowsChange] = useState(() => []) + return ( - - - + + + + + {selectedRows?.length > 0 && ( + + {selectedRows?.length === 1 ? ( + + ) : ( + + ( + toggleRowSelected(false)} + /> + ) + )} + /> + + )} + + )} + + ) } diff --git a/src/fireedge/src/client/containers/VNetworkTemplates/index.js b/src/fireedge/src/client/containers/VNetworkTemplates/index.js index 0292e2cf51..2b9062b6e0 100644 --- a/src/fireedge/src/client/containers/VNetworkTemplates/index.js +++ b/src/fireedge/src/client/containers/VNetworkTemplates/index.js @@ -14,23 +14,52 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ - -import { Container, Box } from '@mui/material' +import { useState } from 'react' +import { Container, Stack, Chip } from '@mui/material' import { VNetworkTemplatesTable } from 'client/components/Tables' +import VNetworkTemplateTabs from 'client/components/Tabs/VNetworkTemplate' +import SplitPane from 'client/components/SplitPane' +import MultipleTags from 'client/components/MultipleTags' function VNetworkTemplates() { + const [selectedRows, onSelectedRowsChange] = useState(() => []) + return ( - - - + + + + + {selectedRows?.length > 0 && ( + + {selectedRows?.length === 1 ? ( + + ) : ( + + ( + toggleRowSelected(false)} + /> + ) + )} + /> + + )} + + )} + + ) } diff --git a/src/fireedge/src/client/containers/VirtualMachines/index.js b/src/fireedge/src/client/containers/VirtualMachines/index.js index 21173a7abe..e95376fe76 100644 --- a/src/fireedge/src/client/containers/VirtualMachines/index.js +++ b/src/fireedge/src/client/containers/VirtualMachines/index.js @@ -26,7 +26,6 @@ import MultipleTags from 'client/components/MultipleTags' function VirtualMachines() { const [selectedRows, onSelectedRowsChange] = useState(() => []) const actions = VmActions() - const dataCy = 'vms' return ( @@ -34,8 +33,6 @@ function VirtualMachines() { {selectedRows?.length > 0 && ( diff --git a/src/fireedge/src/client/containers/VirtualNetworks/index.js b/src/fireedge/src/client/containers/VirtualNetworks/index.js index 7908103e8e..79c2f77b3c 100644 --- a/src/fireedge/src/client/containers/VirtualNetworks/index.js +++ b/src/fireedge/src/client/containers/VirtualNetworks/index.js @@ -14,23 +14,52 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ - -import { Container, Box } from '@mui/material' +import { useState } from 'react' +import { Container, Stack, Chip } from '@mui/material' import { VNetworksTable } from 'client/components/Tables' +import VNetworkTabs from 'client/components/Tabs/VNetwork' +import SplitPane from 'client/components/SplitPane' +import MultipleTags from 'client/components/MultipleTags' function VirtualNetworks() { + const [selectedRows, onSelectedRowsChange] = useState(() => []) + return ( - - - + + + + + {selectedRows?.length > 0 && ( + + {selectedRows?.length === 1 ? ( + + ) : ( + + ( + toggleRowSelected(false)} + /> + ) + )} + /> + + )} + + )} + + ) } diff --git a/src/fireedge/src/client/containers/VmTemplates/Create.js b/src/fireedge/src/client/containers/VmTemplates/Create.js index 418eeb3cc3..b697ce2535 100644 --- a/src/fireedge/src/client/containers/VmTemplates/Create.js +++ b/src/fireedge/src/client/containers/VmTemplates/Create.js @@ -13,46 +13,47 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { JSXElementConstructor } from 'react' +import { ReactElement } from 'react' import { useHistory, useLocation } from 'react-router' import { Container } from '@mui/material' import { useGeneralApi } from 'client/features/General' -import { useVmTemplateApi } from 'client/features/One' +import { + useUpdateTemplateMutation, + useAllocateTemplateMutation, +} from 'client/features/OneApi/vmTemplate' import { CreateForm } from 'client/components/Forms/VmTemplate' import { PATH } from 'client/apps/sunstone/routesOne' -import { isDevelopment } from 'client/utils' /** * Displays the creation or modification form to a VM Template. * - * @returns {JSXElementConstructor} VM Template form + * @returns {ReactElement} VM Template form */ function CreateVmTemplate() { const history = useHistory() const { state: { ID: templateId, NAME } = {} } = useLocation() const { enqueueSuccess } = useGeneralApi() - const { update, allocate } = useVmTemplateApi() + const [update] = useUpdateTemplateMutation() + const [allocate] = useAllocateTemplateMutation() const onSubmit = async (xmlTemplate) => { try { if (!templateId) { - const newTemplateId = await allocate(xmlTemplate) + const newTemplateId = await allocate({ template: xmlTemplate }).unwrap() history.push(PATH.TEMPLATE.VMS.LIST) enqueueSuccess(`VM Template created - #${newTemplateId}`) } else { - await update(templateId, xmlTemplate) + await update({ id: templateId, template: xmlTemplate }) history.push(PATH.TEMPLATE.VMS.LIST) enqueueSuccess(`VM Template updated - #${templateId} ${NAME}`) } - } catch (err) { - isDevelopment() && console.error(err) - } + } catch {} } return ( - + ) diff --git a/src/fireedge/src/client/containers/VmTemplates/Instantiate.js b/src/fireedge/src/client/containers/VmTemplates/Instantiate.js index 7ba4d35170..7f7f3d35c9 100644 --- a/src/fireedge/src/client/containers/VmTemplates/Instantiate.js +++ b/src/fireedge/src/client/containers/VmTemplates/Instantiate.js @@ -13,40 +13,45 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -/* eslint-disable jsdoc/require-jsdoc */ +import { ReactElement } from 'react' import { useHistory, useLocation } from 'react-router' import { Container } from '@mui/material' import { useGeneralApi } from 'client/features/General' -import { useVmTemplateApi } from 'client/features/One' +import { useInstantiateTemplateMutation } from 'client/features/OneApi/vmTemplate' import { InstantiateForm } from 'client/components/Forms/VmTemplate' import { PATH } from 'client/apps/sunstone/routesOne' -import { isDevelopment } from 'client/utils' +/** + * Displays the instantiation form for a VM Template. + * + * @returns {ReactElement} Instantiation form + */ function InstantiateVmTemplate() { const history = useHistory() const { state: { ID: templateId } = {} } = useLocation() const { enqueueInfo } = useGeneralApi() - const { instantiate } = useVmTemplateApi() + const [instantiate] = useInstantiateTemplateMutation() const onSubmit = async ([templateSelected, templates]) => { try { const { ID, NAME } = templateSelected + const templatesWithId = templates.map((t) => ({ id: ID, ...t })) - await Promise.all(templates.map((template) => instantiate(ID, template))) + await Promise.all(templatesWithId.map(instantiate)) - history.push(templateId ? PATH.TEMPLATE.VMS.LIST : PATH.INSTANCE.VMS.LIST) - enqueueInfo( - `VM Template instantiated x${templates.length} - #${ID} ${NAME}` - ) - } catch (err) { - isDevelopment() && console.error(err) - } + templateId + ? history.push(PATH.TEMPLATE.VMS.LIST) + : history.push(PATH.INSTANCE.VMS.LIST) + + const total = templates.length + enqueueInfo(`VM Template instantiated x${total} - #${ID} ${NAME}`) + } catch {} } return ( - + ) diff --git a/src/fireedge/src/client/containers/Zones/index.js b/src/fireedge/src/client/containers/Zones/index.js index 0cbd6e4aff..bec3e55606 100644 --- a/src/fireedge/src/client/containers/Zones/index.js +++ b/src/fireedge/src/client/containers/Zones/index.js @@ -14,23 +14,52 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ /* eslint-disable jsdoc/require-jsdoc */ - -import { Container, Box } from '@mui/material' +import { useState } from 'react' +import { Container, Stack, Chip } from '@mui/material' import { ZonesTable } from 'client/components/Tables' +import ZoneTabs from 'client/components/Tabs/Zone' +import SplitPane from 'client/components/SplitPane' +import MultipleTags from 'client/components/MultipleTags' function Zones() { + const [selectedRows, onSelectedRowsChange] = useState(() => []) + return ( - - - + + + + + {selectedRows?.length > 0 && ( + + {selectedRows?.length === 1 ? ( + + ) : ( + + ( + toggleRowSelected(false)} + /> + ) + )} + /> + + )} + + )} + + ) } diff --git a/src/fireedge/src/client/features/Auth/actions.js b/src/fireedge/src/client/features/Auth/actions.js index 4d077d0191..437478ef90 100644 --- a/src/fireedge/src/client/features/Auth/actions.js +++ b/src/fireedge/src/client/features/Auth/actions.js @@ -18,10 +18,7 @@ import { createAction, createAsyncThunk } from '@reduxjs/toolkit' import { authService } from 'client/features/Auth/services' import { dismissSnackbar } from 'client/features/General/actions' - -import { RESOURCES } from 'client/features/One' -import { getGroups } from 'client/features/One/group/actions' -import { userService } from 'client/features/One/user/services' +import apiUser from 'client/features/OneApi/user' import { httpCodes } from 'server/utils/constants' import { removeStoreData, storage } from 'client/utils' @@ -58,16 +55,11 @@ export const getUser = createAsyncThunk( 'auth/user', async (_, { dispatch, getState }) => { try { - const { auth = {}, one: { [RESOURCES.group]: groups } = {} } = getState() + const { auth = {} } = getState() const user = await authService.getUser() const isOneAdmin = user?.ID === ONEADMIN_ID const userSettings = user?.TEMPLATE?.FIREEDGE ?? {} - const userGroupIds = [user?.GROUPS?.ID].flat() - - if (!groups.some((group) => userGroupIds.includes(group?.ID))) { - await dispatch(getGroups()) - } // Merge user settings with the existing one const settings = { @@ -83,6 +75,7 @@ export const getUser = createAsyncThunk( return { user, settings, isOneAdmin } } catch (error) { + console.log({ error }) dispatch(logout(T.SessionExpired)) } }, @@ -116,7 +109,7 @@ export const changeGroup = createAsyncThunk( const { user } = getState().auth const data = { id: user?.ID, group } - await userService.changeGroup(data) + dispatch(apiUser.endpoints.changeGroup.initiate(data)).reset() dispatch(changeFilter(FILTER_POOL.PRIMARY_GROUP_RESOURCES)) @@ -136,3 +129,7 @@ export const changeGroup = createAsyncThunk( } } ) + +export const changeView = createAction('auth/change-view', (view) => ({ + payload: { view }, +})) diff --git a/src/fireedge/src/client/features/Auth/hooks.js b/src/fireedge/src/client/features/Auth/hooks.js index 8c24dd90e5..7e4755d78f 100644 --- a/src/fireedge/src/client/features/Auth/hooks.js +++ b/src/fireedge/src/client/features/Auth/hooks.js @@ -19,25 +19,32 @@ import { useDispatch, useSelector, shallowEqual } from 'react-redux' import { unwrapResult } from '@reduxjs/toolkit' import * as actions from 'client/features/Auth/actions' -import * as provisionActions from 'client/features/Auth/provision' -import * as sunstoneActions from 'client/features/Auth/sunstone' import { name as authSlice } from 'client/features/Auth/slice' -import { name as oneSlice, RESOURCES } from 'client/features/One/slice' +import apiGroup from 'client/features/OneApi/group' +import apiSystem from 'client/features/OneApi/system' import { RESOURCE_NAMES } from 'client/constants' export const useAuth = () => { const auth = useSelector((state) => state[authSlice], shallowEqual) - const groups = useSelector( - (state) => state[oneSlice][RESOURCES.group], - shallowEqual + const { user, jwt, view, isLoginInProgress } = auth + + const { data: views } = apiSystem.endpoints.getSunstoneViews.useQuery( + undefined, + { skip: !jwt } ) - const { user, jwt, view, views, isLoginInProgress } = auth - - const userGroups = [user?.GROUPS?.ID] - .flat() - .map((id) => groups.find(({ ID }) => ID === id)) - .filter(Boolean) + const { data: userGroups } = apiGroup.endpoints.getGroups.useQuery( + undefined, + { + skip: !jwt, + selectFromResult: ({ data: groups = [] }) => ({ + data: [user?.GROUPS?.ID] + .flat() + .map((id) => groups.find(({ ID }) => ID === id)) + .filter(Boolean), + }), + } + ) const isLogged = !!jwt && !!userGroups?.length && !isLoginInProgress @@ -49,17 +56,26 @@ export const useAuth = () => { * resource_name: string, * actions: object[], * filters: object[], - * info-tabs: object[], + * info-tabs: object, * dialogs: object[] * }} Returns view of resource */ const getResourceView = useCallback( (resourceName) => - views?.[view]?.find(({ resource_name: name }) => name === resourceName), + views?.[view]?.find( + ({ resource_name: name }) => + String(name).toLowerCase() === String(resourceName).toLowerCase() + ), [view] ) - return { ...auth, groups: userGroups, isLogged, getResourceView } + return { + ...auth, + groups: userGroups, + isLogged, + getResourceView, + views, + } } export const useAuthApi = () => { @@ -73,15 +89,9 @@ export const useAuthApi = () => { return { login: (user) => unwrapDispatch(actions.login(user)), getAuthUser: () => dispatch(actions.getUser()), - changeGroup: (data) => unwrapDispatch(actions.changeGroup(data)), + changeGroup: (group) => unwrapDispatch(actions.changeGroup(group)), logout: () => dispatch(actions.logout()), - getProviderConfig: () => - unwrapDispatch(provisionActions.getProviderConfig()), - - getSunstoneViews: () => unwrapDispatch(sunstoneActions.getSunstoneViews()), - getSunstoneConfig: () => - unwrapDispatch(sunstoneActions.getSunstoneConfig()), - changeView: (data) => dispatch(sunstoneActions.changeView(data)), + changeView: (view) => dispatch(actions.changeView(view)), } } diff --git a/src/fireedge/src/client/features/Auth/provision.js b/src/fireedge/src/client/features/Auth/provision.js deleted file mode 100644 index d57f32131f..0000000000 --- a/src/fireedge/src/client/features/Auth/provision.js +++ /dev/null @@ -1,37 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { createAsyncThunk } from '@reduxjs/toolkit' - -import { authService } from 'client/features/Auth/services' -import { logout } from 'client/features/Auth/actions' - -import { httpCodes } from 'server/utils/constants' -import { T } from 'client/constants' - -export const getProviderConfig = createAsyncThunk( - 'provision/provider-config', - async (_, { dispatch }) => { - try { - const config = (await authService.getProviderConfig()) ?? {} - - return { providerConfig: config } - } catch (error) { - error?.status === httpCodes.unauthorized.id && - dispatch(logout(T.SessionExpired)) - } - } -) diff --git a/src/fireedge/src/client/features/Auth/services.js b/src/fireedge/src/client/features/Auth/services.js index d81038a906..1eed1e62ac 100644 --- a/src/fireedge/src/client/features/Auth/services.js +++ b/src/fireedge/src/client/features/Auth/services.js @@ -51,37 +51,4 @@ export const authService = { return res?.data?.USER ?? {} }, - /** - * @returns {object} Provider configuration - * @throws Fails when response isn't code 200 - */ - getProviderConfig: async () => { - const res = await RestClient.request({ url: '/api/provider/config' }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - /** - * @returns {object} Views available for the user authenticated - * @throws Fails when response isn't code 200 - */ - getSunstoneViews: async () => { - const res = await RestClient.request({ url: '/api/sunstone/views' }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - /** - * @returns {object} Sunstone configuration - * @throws Fails when response isn't code 200 - */ - getSunstoneConfig: async () => { - const res = await RestClient.request({ url: '/api/sunstone/config' }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, } diff --git a/src/fireedge/src/client/features/Auth/slice.js b/src/fireedge/src/client/features/Auth/slice.js index 71280f3efb..a1689d8e20 100644 --- a/src/fireedge/src/client/features/Auth/slice.js +++ b/src/fireedge/src/client/features/Auth/slice.js @@ -21,13 +21,8 @@ import { logout, changeFilter, changeGroup, -} from 'client/features/Auth/actions' -import { getProviderConfig } from 'client/features/Auth/provision' -import { - getSunstoneViews, - getSunstoneConfig, changeView, -} from 'client/features/Auth/sunstone' +} from 'client/features/Auth/actions' import { JWT_NAME, FILTER_POOL, @@ -70,11 +65,6 @@ const { name, actions, reducer } = createSlice({ login.fulfilled.type, getUser.fulfilled.type, changeGroup.fulfilled.type, - // provision - getProviderConfig.fulfilled.type, - // sunstone - getSunstoneViews.fulfilled.type, - getSunstoneConfig.fulfilled.type, changeView.type, ].includes(type), (state, { payload }) => ({ ...state, ...payload }) diff --git a/src/fireedge/src/client/features/Auth/sunstone.js b/src/fireedge/src/client/features/Auth/sunstone.js deleted file mode 100644 index 2c78086917..0000000000 --- a/src/fireedge/src/client/features/Auth/sunstone.js +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { createAsyncThunk, createAction } from '@reduxjs/toolkit' - -import { authService } from 'client/features/Auth/services' -import { logout } from 'client/features/Auth/actions' - -import { httpCodes } from 'server/utils/constants' -import { T } from 'client/constants' - -export const getSunstoneViews = createAsyncThunk( - 'sunstone/views', - async (_, { dispatch }) => { - try { - const views = (await authService.getSunstoneViews()) ?? {} - - return { - views, - view: Object.keys(views)[0], - } - } catch (error) { - error?.status === httpCodes.unauthorized.id && - dispatch(logout(T.SessionExpired)) - } - } -) - -export const getSunstoneConfig = createAsyncThunk( - 'sunstone/config', - async (_, { dispatch }) => { - try { - const config = (await authService.getSunstoneConfig()) ?? {} - - return { config } - } catch (error) { - error?.status === httpCodes.unauthorized.id && - dispatch(logout(T.SessionExpired)) - } - } -) - -export const changeView = createAction('sunstone/change-view', (view) => ({ - payload: { view }, -})) diff --git a/src/fireedge/src/client/features/One/actions.js b/src/fireedge/src/client/features/One/actions.js deleted file mode 100644 index 7ebab0de36..0000000000 --- a/src/fireedge/src/client/features/One/actions.js +++ /dev/null @@ -1,21 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from '@reduxjs/toolkit' - -export const updateResourceFromFetch = createAction( - 'update-resource-from-fetch', - ({ data, resource }) => ({ payload: { type: resource, data } }) -) diff --git a/src/fireedge/src/client/features/One/application/actions.js b/src/fireedge/src/client/features/One/application/actions.js deleted file mode 100644 index 11d4a0fc71..0000000000 --- a/src/fireedge/src/client/features/One/application/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { applicationService } from 'client/features/One/application/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.document} */ -const SERVICE_APPLICATION = 'document[100]' - -export const getApplication = createAction( - `${SERVICE_APPLICATION}/detail`, - applicationService.getApplication -) - -export const getApplications = createAction( - `${SERVICE_APPLICATION}/pool`, - applicationService.getApplications, - (response) => ({ [RESOURCES.document[100]]: response }) -) diff --git a/src/fireedge/src/client/features/One/application/hooks.js b/src/fireedge/src/client/features/One/application/hooks.js deleted file mode 100644 index 0dbc4ed599..0000000000 --- a/src/fireedge/src/client/features/One/application/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/application/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useApplication = () => - useSelector((state) => state[name]?.[RESOURCES.document[100]] ?? []) - -export const useApplicationApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getApplication: (id) => unwrapDispatch(actions.getApplication({ id })), - getApplications: () => unwrapDispatch(actions.getApplications()), - } -} diff --git a/src/fireedge/src/client/features/One/application/services.js b/src/fireedge/src/client/features/One/application/services.js deleted file mode 100644 index f8efa28cc3..0000000000 --- a/src/fireedge/src/client/features/One/application/services.js +++ /dev/null @@ -1,54 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { SERVICE } from 'server/routes/api/oneflow/basepath' -import { httpCodes } from 'server/utils/constants' -import { RestClient } from 'client/utils' - -export const applicationService = { - /** - * Retrieves information for the service. - * - * @param {object} data - Request parameters - * @param {string} data.id - Service id - * @returns {object} Get service identified by id - * @throws Fails when response isn't code 200 - */ - getApplication: async ({ id }) => { - const res = await RestClient.request({ - url: `/api/${SERVICE}/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.DOCUMENT ?? {} - }, - - /** - * Retrieves information for all services. - * - * @returns {object} Get list of services - * @throws Fails when response isn't code 200 - */ - getApplications: async () => { - const res = await RestClient.request({ - url: `/api/${SERVICE}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/applicationTemplate/actions.js b/src/fireedge/src/client/features/One/applicationTemplate/actions.js deleted file mode 100644 index d42583f35c..0000000000 --- a/src/fireedge/src/client/features/One/applicationTemplate/actions.js +++ /dev/null @@ -1,47 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { applicationTemplateService } from 'client/features/One/applicationTemplate/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.document} */ -const SERVICE_TEMPLATE = 'document[101]' - -export const getApplicationTemplate = createAction( - `${SERVICE_TEMPLATE}/detail`, - applicationTemplateService.getApplicationTemplate -) - -export const getApplicationsTemplates = createAction( - `${SERVICE_TEMPLATE}/pool`, - applicationTemplateService.getApplicationsTemplates, - (response) => ({ [RESOURCES.document[101]]: response }) -) - -export const createApplicationTemplate = createAction( - `${SERVICE_TEMPLATE}/create`, - applicationTemplateService.createApplicationTemplate -) - -export const updateApplicationTemplate = createAction( - `${SERVICE_TEMPLATE}/update`, - applicationTemplateService.updateApplicationTemplate -) - -export const instantiateApplicationTemplate = createAction( - `${SERVICE_TEMPLATE}/instantiate`, - applicationTemplateService.instantiateApplicationTemplate -) diff --git a/src/fireedge/src/client/features/One/applicationTemplate/hooks.js b/src/fireedge/src/client/features/One/applicationTemplate/hooks.js deleted file mode 100644 index dacc553046..0000000000 --- a/src/fireedge/src/client/features/One/applicationTemplate/hooks.js +++ /dev/null @@ -1,49 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/applicationTemplate/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useApplicationTemplate = () => - useSelector((state) => state[name]?.[RESOURCES.document[101]] ?? []) - -export const useApplicationTemplateApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getApplicationTemplate: (id) => - unwrapDispatch(actions.getApplicationTemplate({ id })), - getApplicationsTemplates: () => - unwrapDispatch(actions.getApplicationsTemplates()), - createApplicationTemplate: (data) => - unwrapDispatch(actions.createApplicationTemplate({ data })), - - updateApplicationTemplate: (id, data) => - unwrapDispatch(actions.updateApplicationTemplate({ id, data })), - - instantiateApplicationTemplate: (id, data) => - unwrapDispatch(actions.instantiateApplicationTemplate({ id, data })), - } -} diff --git a/src/fireedge/src/client/features/One/applicationTemplate/services.js b/src/fireedge/src/client/features/One/applicationTemplate/services.js deleted file mode 100644 index b8c4141602..0000000000 --- a/src/fireedge/src/client/features/One/applicationTemplate/services.js +++ /dev/null @@ -1,121 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { SERVICE_TEMPLATE } from 'server/routes/api/oneflow/basepath' -import { httpCodes, defaults } from 'server/utils/constants' -import { RestClient } from 'client/utils' - -const { POST, PUT } = defaults?.httpMethod || {} - -export const applicationTemplateService = { - /** - * Retrieves information for the service template. - * - * @param {object} data - Request parameters - * @param {string} data.id - Service template id - * @returns {object} Get service template identified by id - * @throws Fails when response isn't code 200 - */ - getApplicationTemplate: ({ id }) => { - const res = RestClient.request({ - url: `/api/${SERVICE_TEMPLATE}/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.DOCUMENT ?? {} - }, - - /** - * @returns {object} Get list of service templates - * @throws Fails when response isn't code 200 - */ - getApplicationsTemplates: async () => { - const res = await RestClient.request({ - url: `/api/${SERVICE_TEMPLATE}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat() - }, - - /** - * Retrieves information for all service templates. - * - * @param {object} params - Request parameters - * @param {object} params.data - Data of new application template - * @returns {object} Object of document created - * @throws Fails when response isn't code 200 - */ - createApplicationTemplate: async ({ data = {} }) => { - const res = await RestClient.request({ - data, - method: POST, - url: `/api/${SERVICE_TEMPLATE}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.DOCUMENT ?? {} - }, - - /** - * Update the service template. - * - * @param {object} params - Request parameters - * @param {object} params.id - Service template id - * @param {object} params.data - Updated data - * @returns {object} Object of document updated - * @throws Fails when response isn't code 200 - */ - updateApplicationTemplate: ({ id, data = {} }) => { - const res = RestClient.request({ - data, - method: PUT, - url: `/api/${SERVICE_TEMPLATE}/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.DOCUMENT ?? {} - }, - - /** - * Perform instantiate action on the service template. - * - * @param {object} params - Request parameters - * @param {object} params.id - Service template id - * @param {object} params.data - Additional parameters to be passed inside `params` - * @returns {Response} Response 201 - * @throws Fails when response isn't code 200 - */ - instantiateApplicationTemplate: ({ id, data = {} }) => { - const res = RestClient.request({ - data: { - action: { - perform: 'instantiate', - params: { merge_template: data }, - }, - }, - method: PUT, - url: `/api/${SERVICE_TEMPLATE}/action/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, -} diff --git a/src/fireedge/src/client/features/One/cluster/actions.js b/src/fireedge/src/client/features/One/cluster/actions.js deleted file mode 100644 index 6088b09e25..0000000000 --- a/src/fireedge/src/client/features/One/cluster/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { clusterService } from 'client/features/One/cluster/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.cluster} */ -const CLUSTER = 'cluster' - -export const getCluster = createAction( - `${CLUSTER}/detail`, - clusterService.getCluster -) - -export const getClusters = createAction( - `${CLUSTER}/pool`, - clusterService.getClusters, - (response) => ({ [RESOURCES.cluster]: response }) -) diff --git a/src/fireedge/src/client/features/One/cluster/hooks.js b/src/fireedge/src/client/features/One/cluster/hooks.js deleted file mode 100644 index 6fd2396f76..0000000000 --- a/src/fireedge/src/client/features/One/cluster/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/cluster/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useCluster = () => - useSelector((state) => state[name]?.[RESOURCES.cluster] ?? []) - -export const useClusterApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getCluster: (id) => unwrapDispatch(actions.getCluster({ id })), - getClusters: () => unwrapDispatch(actions.getClusters()), - } -} diff --git a/src/fireedge/src/client/features/One/cluster/services.js b/src/fireedge/src/client/features/One/cluster/services.js deleted file mode 100644 index 7e00a9514f..0000000000 --- a/src/fireedge/src/client/features/One/cluster/services.js +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/cluster' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const clusterService = { - /** - * Retrieves information for the cluster. - * - * @param {object} data - Request parameters - * @param {string} data.id - Cluster id - * @returns {object} Get cluster identified by id - * @throws Fails when response isn't code 200 - */ - getCluster: async ({ id }) => { - const name = Actions.CLUSTER_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.CLUSTER ?? {} - }, - - /** - * Retrieves information for all the clusters in the pool. - * - * @returns {Array} List of clusters - * @throws Fails when response isn't code 200 - */ - getClusters: async () => { - const name = Actions.CLUSTER_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.CLUSTER_POOL?.CLUSTER ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/datastore/actions.js b/src/fireedge/src/client/features/One/datastore/actions.js deleted file mode 100644 index 3ac31fec46..0000000000 --- a/src/fireedge/src/client/features/One/datastore/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { datastoreService } from 'client/features/One/datastore/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.datastore} */ -const DATASTORE = 'datastore' - -export const getDatastore = createAction( - `${DATASTORE}/detail`, - datastoreService.getDatastore -) - -export const getDatastores = createAction( - `${DATASTORE}/pool`, - datastoreService.getDatastores, - (response) => ({ [RESOURCES.datastore]: response }) -) diff --git a/src/fireedge/src/client/features/One/datastore/hooks.js b/src/fireedge/src/client/features/One/datastore/hooks.js deleted file mode 100644 index b22f59aeb5..0000000000 --- a/src/fireedge/src/client/features/One/datastore/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/datastore/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useDatastore = () => - useSelector((state) => state[name]?.[RESOURCES.datastore] ?? []) - -export const useDatastoreApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getDatastore: (id) => unwrapDispatch(actions.getDatastore({ id })), - getDatastores: (options) => unwrapDispatch(actions.getDatastores(options)), - } -} diff --git a/src/fireedge/src/client/features/One/datastore/services.js b/src/fireedge/src/client/features/One/datastore/services.js deleted file mode 100644 index 7ab0ebecd0..0000000000 --- a/src/fireedge/src/client/features/One/datastore/services.js +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/datastore' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const datastoreService = { - /** - * Retrieves information for the datastore. - * - * @param {object} data - Request parameters - * @param {string} data.id - Datastore id - * @returns {object} Get datastore identified by id - * @throws Fails when response isn't code 200 - */ - getDatastore: async ({ id }) => { - const name = Actions.DATASTORE_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.DATASTORE ?? {} - }, - - /** - * Retrieves information for all datastores in the pool. - * - * @returns {object} Get list of datastores - * @throws Fails when response isn't code 200 - */ - getDatastores: async () => { - const name = Actions.DATASTORE_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.DATASTORE_POOL?.DATASTORE ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/group/actions.js b/src/fireedge/src/client/features/One/group/actions.js deleted file mode 100644 index a0417ee959..0000000000 --- a/src/fireedge/src/client/features/One/group/actions.js +++ /dev/null @@ -1,29 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { groupService } from 'client/features/One/group/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.group} */ -const GROUP = 'group' - -export const getGroup = createAction(`${GROUP}/detail`, groupService.getGroup) - -export const getGroups = createAction( - `${GROUP}/pool`, - groupService.getGroups, - (response) => ({ [RESOURCES.group]: response }) -) diff --git a/src/fireedge/src/client/features/One/group/hooks.js b/src/fireedge/src/client/features/One/group/hooks.js deleted file mode 100644 index 290cacc133..0000000000 --- a/src/fireedge/src/client/features/One/group/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/group/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useGroup = () => - useSelector((state) => state[name]?.[RESOURCES.group] ?? []) - -export const useGroupApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getGroup: (id) => unwrapDispatch(actions.getGroup({ id })), - getGroups: () => unwrapDispatch(actions.getGroups()), - } -} diff --git a/src/fireedge/src/client/features/One/group/services.js b/src/fireedge/src/client/features/One/group/services.js deleted file mode 100644 index 3038d953ff..0000000000 --- a/src/fireedge/src/client/features/One/group/services.js +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/group' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const groupService = { - /** - * Retrieves information for the group. - * - * @param {object} data - Request parameters - * @param {string} data.id - Group id - * @returns {object} Get group identified by id - * @throws Fails when response isn't code 200 - */ - getGroup: async ({ id }) => { - const name = Actions.GROUP_INFO - const command = { name, ...Commands[name] } - const { url, options } = requestConfig({ id }, command) - - const res = await RestClient.get(url, options) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.GROUP ?? {} - }, - - /** - * Retrieves information for all the groups in the pool. - * - * @returns {object} Get list of groups - * @throws Fails when response isn't code 200 - */ - getGroups: async () => { - const name = Actions.GROUP_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.GROUP_POOL?.GROUP ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/hooks.js b/src/fireedge/src/client/features/One/hooks.js deleted file mode 100644 index d94a1b1dc1..0000000000 --- a/src/fireedge/src/client/features/One/hooks.js +++ /dev/null @@ -1,41 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useSelector, shallowEqual } from 'react-redux' -import { name } from 'client/features/One/slice' - -export const useOne = () => useSelector((state) => state[name], shallowEqual) - -export * from 'client/features/One/application/hooks' -export * from 'client/features/One/applicationTemplate/hooks' -export * from 'client/features/One/cluster/hooks' -export * from 'client/features/One/datastore/hooks' -export * from 'client/features/One/group/hooks' -export * from 'client/features/One/host/hooks' -export * from 'client/features/One/image/hooks' -export * from 'client/features/One/marketplace/hooks' -export * from 'client/features/One/marketplaceApp/hooks' -export * from 'client/features/One/provider/hooks' -export * from 'client/features/One/provision/hooks' -export * from 'client/features/One/system/hooks' -export * from 'client/features/One/user/hooks' -export * from 'client/features/One/vm/hooks' -export * from 'client/features/One/vmGroup/hooks' -export * from 'client/features/One/vmTemplate/hooks' -export * from 'client/features/One/vnetwork/hooks' -export * from 'client/features/One/vnetworkTemplate/hooks' -export * from 'client/features/One/vrouter/hooks' -export * from 'client/features/One/zone/hooks' diff --git a/src/fireedge/src/client/features/One/host/actions.js b/src/fireedge/src/client/features/One/host/actions.js deleted file mode 100644 index 2d14d46d75..0000000000 --- a/src/fireedge/src/client/features/One/host/actions.js +++ /dev/null @@ -1,45 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { hostService } from 'client/features/One/host/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.host} */ -const HOST = 'host' - -export const getHost = createAction(`${HOST}/detail`, hostService.getHost) - -export const getHosts = createAction( - `${HOST}/pool`, - hostService.getHosts, - (response) => ({ [RESOURCES.host]: response }) -) - -export const allocate = createAction(`${HOST}/allocate`, hostService.allocate) -export const remove = createAction(`${HOST}/delete`, hostService.delete) -export const enable = createAction(`${HOST}/enable`, hostService.enable) -export const disable = createAction(`${HOST}/disable`, hostService.disable) -export const offline = createAction(`${HOST}/offline`, hostService.offline) -export const update = createAction(`${HOST}/update`, hostService.update) -export const rename = createAction(`${HOST}/rename`, hostService.rename) -export const monitoring = createAction( - `${HOST}/monitoring`, - hostService.monitoring -) -export const monitoringPool = createAction( - `${HOST}/monitoring-pool`, // ends with "-pool" to differentiate with resource pool - hostService.monitoringPool -) diff --git a/src/fireedge/src/client/features/One/host/hooks.js b/src/fireedge/src/client/features/One/host/hooks.js deleted file mode 100644 index b587a540b8..0000000000 --- a/src/fireedge/src/client/features/One/host/hooks.js +++ /dev/null @@ -1,51 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/host/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useHost = () => - useSelector((state) => state[name]?.[RESOURCES.host]) - -export const useHostApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getHost: (id) => unwrapDispatch(actions.getHost({ id })), - getHosts: (options) => unwrapDispatch(actions.getHosts(options)), - allocate: (data) => unwrapDispatch(actions.allocate(data)), - remove: (id) => unwrapDispatch(actions.remove({ id })), - enable: (id) => unwrapDispatch(actions.enable({ id })), - disable: (id) => unwrapDispatch(actions.disable({ id })), - offline: (id) => unwrapDispatch(actions.offline({ id })), - update: (id, template, replace) => - unwrapDispatch(actions.update({ id, template, replace })), - rename: (id, newName) => - unwrapDispatch(actions.rename({ id, name: newName })), - getMonitoring: (id) => unwrapDispatch(actions.monitoring({ id })), - getMonitoringPool: (seconds) => - unwrapDispatch(actions.monitoringPool({ seconds })), - } -} diff --git a/src/fireedge/src/client/features/One/host/services.js b/src/fireedge/src/client/features/One/host/services.js deleted file mode 100644 index f2fd0cec31..0000000000 --- a/src/fireedge/src/client/features/One/host/services.js +++ /dev/null @@ -1,253 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/host' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const hostService = { - /** - * Retrieves information for the host. - * - * @param {object} data - Request parameters - * @param {string} data.id - Host id - * @returns {object} Get host identified by id - * @throws Fails when response isn't code 200 - */ - getHost: async ({ id }) => { - const name = Actions.HOST_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.HOST ?? {} - }, - - /** - * Retrieves information for all the hosts in the pool. - * - * @returns {object} Get list of hosts - * @throws Fails when response isn't code 200 - */ - getHosts: async () => { - const name = Actions.HOST_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.HOST_POOL?.HOST ?? []].flat() - }, - /** - * Allocates a new host in OpenNebula. - * - * @param {object} params - Request params - * @param {string} params.hostname - Hostname of the machine we want to add - * @param {string} params.imMad - * - The name of the information manager (im_mad_name), - * this values are taken from the oned.conf with the tag name IM_MAD (name) - * @param {string} params.vmmMad - * - The name of the virtual machine manager mad name (vmm_mad_name), - * this values are taken from the oned.conf with the tag name VM_MAD (name) - * @param {string|number} [params.cluster] - The cluster ID - * @returns {number} Host id - * @throws Fails when response isn't code 200 - */ - allocate: async (params) => { - const name = Actions.HOST_ALLOCATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Deletes the given host from the pool. - * - * @param {object} params - Request params - * @param {number|string} params.id - Host id - * @returns {number} Host id - * @throws Fails when response isn't code 200 - */ - delete: async (params) => { - const name = Actions.HOST_DELETE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Sets the status of the host to enabled. - * - * @param {object} params - Request params - * @param {number|string} params.id - Host id - * @returns {number} Host id - * @throws Fails when response isn't code 200 - */ - enable: async (params) => { - const name = Actions.HOST_STATUS - const command = { name, ...Commands[name] } - const config = requestConfig({ ...params, status: 0 }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Sets the status of the host to disabled. - * - * @param {object} params - Request params - * @param {number|string} params.id - Host id - * @returns {number} Host id - * @throws Fails when response isn't code 200 - */ - disable: async (params) => { - const name = Actions.HOST_STATUS - const command = { name, ...Commands[name] } - const config = requestConfig({ ...params, status: 1 }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Sets the status of the host to offline. - * - * @param {object} params - Request params - * @param {number|string} params.id - Host id - * @returns {number} Host id - * @throws Fails when response isn't code 200 - */ - offline: async (params) => { - const name = Actions.HOST_STATUS - const command = { name, ...Commands[name] } - const config = requestConfig({ ...params, status: 2 }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Replaces the host’s template contents.. - * - * @param {object} params - Request params - * @param {number|string} params.id - Host id - * @param {string} params.template - The new template contents - * @param {0|1} params.replace - * - Update type: - * ``0``: Replace the whole template. - * ``1``: Merge new template with the existing one. - * @returns {number} Host id - * @throws Fails when response isn't code 200 - */ - update: async (params) => { - const name = Actions.HOST_UPDATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Renames a host. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Host id - * @param {string} params.name - New name - * @returns {number} Host id - * @throws Fails when response isn't code 200 - */ - rename: async (params) => { - const name = Actions.HOST_RENAME - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Returns the host monitoring records. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Host id - * @returns {string} The monitoring information string / The error string - * @throws Fails when response isn't code 200 - */ - monitoring: async (params) => { - const name = Actions.HOST_MONITORING - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Returns all the host monitoring records. - * - * @param {object} params - Request parameters - * @param {string|number} [params.seconds] - * - Retrieve monitor records in the last num seconds. - * ``0``: Only the last record. - * ``-1``: All records. - * @returns {string} The monitoring information string / The error string - * @throws Fails when response isn't code 200 - */ - monitoringPool: async (params) => { - const name = Actions.HOST_POOL_MONITORING - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, -} diff --git a/src/fireedge/src/client/features/One/image/actions.js b/src/fireedge/src/client/features/One/image/actions.js deleted file mode 100644 index a6d63ef559..0000000000 --- a/src/fireedge/src/client/features/One/image/actions.js +++ /dev/null @@ -1,29 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { imageService } from 'client/features/One/image/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.image} */ -const IMAGE = 'image' - -export const getImage = createAction(`${IMAGE}/detail`, imageService.getImage) - -export const getImages = createAction( - `${IMAGE}/pool`, - imageService.getImages, - (response) => ({ [RESOURCES.image]: response }) -) diff --git a/src/fireedge/src/client/features/One/image/hooks.js b/src/fireedge/src/client/features/One/image/hooks.js deleted file mode 100644 index f7e6eb4e47..0000000000 --- a/src/fireedge/src/client/features/One/image/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/image/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useImage = () => - useSelector((state) => state[name]?.[RESOURCES.image] ?? []) - -export const useImageApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getImage: (id) => unwrapDispatch(actions.getImage({ id })), - getImages: () => unwrapDispatch(actions.getImages()), - } -} diff --git a/src/fireedge/src/client/features/One/image/services.js b/src/fireedge/src/client/features/One/image/services.js deleted file mode 100644 index d152df92e5..0000000000 --- a/src/fireedge/src/client/features/One/image/services.js +++ /dev/null @@ -1,63 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/image' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const imageService = { - /** - * Retrieves information for the image. - * - * @param {object} data - Request parameters - * @param {string} data.id - Image id - * @returns {object} Get image identified by id - * @throws Fails when response isn't code 200 - */ - getImage: async ({ id }) => { - const name = Actions.IMAGE_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.IMAGE ?? {} - }, - - /** - * Retrieves information for all or part of the - * images in the pool. - * - * @param {object} data - Request params - * @param {string} data.filter - Filter flag - * @param {number} data.start - Range start ID - * @param {number} data.end - Range end ID - * @returns {object} Get list of images - * @throws Fails when response isn't code 200 - */ - getImages: async ({ filter, start, end }) => { - const name = Actions.IMAGE_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ filter, start, end }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.IMAGE_POOL?.IMAGE ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/index.js b/src/fireedge/src/client/features/One/index.js deleted file mode 100644 index cb8d3e5822..0000000000 --- a/src/fireedge/src/client/features/One/index.js +++ /dev/null @@ -1,18 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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. * - * ------------------------------------------------------------------------- */ -export * from 'client/features/One/slice' -export * from 'client/features/One/hooks' -export * from 'client/features/One/actions' diff --git a/src/fireedge/src/client/features/One/marketplace/actions.js b/src/fireedge/src/client/features/One/marketplace/actions.js deleted file mode 100644 index 063824d19f..0000000000 --- a/src/fireedge/src/client/features/One/marketplace/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { marketplaceService } from 'client/features/One/marketplace/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.marketplace} */ -const MARKETPLACE = 'marketplace' - -export const getMarketplace = createAction( - `${MARKETPLACE}/detail`, - marketplaceService.getMarketplace -) - -export const getMarketplaces = createAction( - `${MARKETPLACE}/pool`, - marketplaceService.getMarketplaces, - (response) => ({ [RESOURCES.marketplace]: response }) -) diff --git a/src/fireedge/src/client/features/One/marketplace/hooks.js b/src/fireedge/src/client/features/One/marketplace/hooks.js deleted file mode 100644 index 357acb3b3a..0000000000 --- a/src/fireedge/src/client/features/One/marketplace/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/marketplace/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useMarketplace = () => - useSelector((state) => state[name]?.[RESOURCES.marketplace] ?? []) - -export const useMarketplaceApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getMarketplace: (id) => unwrapDispatch(actions.getMarketplace({ id })), - getMarketplaces: () => unwrapDispatch(actions.getMarketplaces()), - } -} diff --git a/src/fireedge/src/client/features/One/marketplace/services.js b/src/fireedge/src/client/features/One/marketplace/services.js deleted file mode 100644 index 5b18015e47..0000000000 --- a/src/fireedge/src/client/features/One/marketplace/services.js +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/market' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const marketplaceService = { - /** - * Retrieves information for the marketplace. - * - * @param {object} data - Request parameters - * @param {string} data.id - Marketplace id - * @returns {object} Get marketplace identified by id - * @throws Fails when response isn't code 200 - */ - getMarketplace: async ({ id }) => { - const name = Actions.MARKET_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.MARKETPLACE ?? {} - }, - - /** - * Retrieves information for all marketplaces. - * - * @returns {object} Get list of marketplaces - * @throws Fails when response isn't code 200 - */ - getMarketplaces: async () => { - const name = Actions.MARKET_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.MARKETPLACE_POOL?.MARKETPLACE ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/marketplaceApp/actions.js b/src/fireedge/src/client/features/One/marketplaceApp/actions.js deleted file mode 100644 index e8ca5adc7e..0000000000 --- a/src/fireedge/src/client/features/One/marketplaceApp/actions.js +++ /dev/null @@ -1,52 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { marketplaceAppService } from 'client/features/One/marketplaceApp/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.app} */ -const APP = 'app' - -export const getMarketplaceApp = createAction( - `${APP}/detail`, - marketplaceAppService.getMarketplaceApp -) - -export const getMarketplaceApps = createAction( - `${APP}/pool`, - marketplaceAppService.getMarketplaceApps, - (response) => ({ [RESOURCES.app]: response }) -) - -export const getDockerHubTags = createAction( - `${APP}/dockerhub-tags`, - marketplaceAppService.getDockerHubTags -) - -export const exportApp = createAction( - `${APP}/export`, - marketplaceAppService.export -) - -export const create = createAction( - `${APP}/create`, - marketplaceAppService.create -) - -export const importApp = createAction( - `${APP}/import`, - marketplaceAppService.import -) diff --git a/src/fireedge/src/client/features/One/marketplaceApp/hooks.js b/src/fireedge/src/client/features/One/marketplaceApp/hooks.js deleted file mode 100644 index f915a43742..0000000000 --- a/src/fireedge/src/client/features/One/marketplaceApp/hooks.js +++ /dev/null @@ -1,48 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/marketplaceApp/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useMarketplaceApp = () => - useSelector((state) => state[name]?.[RESOURCES.app]) - -export const useMarketplaceAppApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getMarketplaceApp: (id) => - unwrapDispatch(actions.getMarketplaceApp({ id })), - getMarketplaceApps: () => unwrapDispatch(actions.getMarketplaceApps()), - getDockerHubTags: (options) => - unwrapDispatch(actions.getDockerHubTags(options)), - exportApp: (id, data) => unwrapDispatch(actions.exportApp({ id, ...data })), - create: (id, template) => unwrapDispatch(actions.create({ id, template })), - importVm: (id, data) => - unwrapDispatch(actions.importApp('vm', { id, ...data })), - importVmTemplate: (id, data) => - unwrapDispatch(actions.importApp('template', { id, ...data })), - } -} diff --git a/src/fireedge/src/client/features/One/marketplaceApp/services.js b/src/fireedge/src/client/features/One/marketplaceApp/services.js deleted file mode 100644 index e5eacf788e..0000000000 --- a/src/fireedge/src/client/features/One/marketplaceApp/services.js +++ /dev/null @@ -1,161 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/marketapp' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const marketplaceAppService = { - /** - * Retrieves information for the marketplace app. - * - * @param {object} data - Request parameters - * @param {string} data.id - Marketplace apps id - * @returns {object} Get marketplace app identified by id - * @throws Fails when response isn't code 200 - */ - getMarketplaceApp: async ({ id }) => { - const name = Actions.MARKETAPP_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.MARKETPLACEAPP ?? {} - }, - - /** - * Retrieves information for all or part of the - * marketplace apps in the pool. - * - * @param {object} data - Request params - * @param {string} data.filter - Filter flag - * @param {number} data.start - Range start ID - * @param {number} data.end - Range end ID - * @returns {Array} List of marketplace apps - * @throws Fails when response isn't code 200 - */ - getMarketplaceApps: async ({ filter, start, end }) => { - const name = Actions.MARKETAPP_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ filter, start, end }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.MARKETPLACEAPP_POOL?.MARKETPLACEAPP ?? []].flat() - }, - - /** - * Retrieves DockerHub tags information for marketplace app. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - App id - * @param {string|number} [params.page] - Number of page - * @returns {object[]} List of DockerHub tags - * @throws Fails when response isn't code 200 - */ - getDockerHubTags: async ({ id, page }) => { - const res = await RestClient.request({ - url: `/api/marketapp/dockertags/${id}`, - params: { page }, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Exports the marketplace app to the OpenNebula cloud. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - App id - * @param {string} params.name - Image name - * @param {string|number} params.datastore - Datastore id or name - * @param {string|number} params.file - File datastore id or name - * @param {string} params.tag - DockerHub image tag (default latest) - * @param {string|number} params.template - Associate with VM template - * @param {boolean} params.associated - If `false`, Do not export associated VM templates/images - * @param {string} params.vmname - The name for the new VM Template, if the App contains one - * @returns {number} Template and image ids - * @throws Fails when response isn't code 200 - */ - export: async ({ id, ...data }) => { - const res = await RestClient.request({ - url: `/api/marketapp/export/${id}`, - method: 'POST', - data, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Allocates a new marketplace app in OpenNebula. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Marketplace id - * @param {string} params.template - A string containing the template of the marketplace app - * @returns {number} App id - * @throws Fails when response isn't code 200 - */ - create: async (params) => { - const name = Actions.MARKETAPP_ALLOCATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Imports a VM or VM Template into the marketplace. - * - * @param {'vm'|'template'} resourceName - Type of resource - * @param {object} params - Request parameters - * @param {string|number} params.id - VM or VM Template id - * @param {string|number} params.marketId - Market to import all objects - * @param {boolean} params.associated - If `true`, don't import associated VM templates/images - * @param {string} params.vmname - Selects the name for the new VM Template, if the App contains one - * @returns {number} App id - * @throws Fails when response isn't code 200 - */ - import: async (resourceName, { id, ...data }) => { - if (!['vm', 'template'].includes(resourceName)) { - throw Error(`Invalid resource to import: ${resourceName}`) - } - - const { marketId, associated, vmname } = data - - const res = await RestClient.request({ - url: `/api/marketapp/${resourceName}import/${id}`, - method: 'POST', - data: { marketId, associated, vmname }, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, -} diff --git a/src/fireedge/src/client/features/One/provider/actions.js b/src/fireedge/src/client/features/One/provider/actions.js deleted file mode 100644 index 97f8d898d5..0000000000 --- a/src/fireedge/src/client/features/One/provider/actions.js +++ /dev/null @@ -1,43 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { providerService } from 'client/features/One/provider/services' -import { RESOURCES } from 'client/features/One/slice' - -export const getProvider = createAction('provider', providerService.getProvider) - -export const getProviders = createAction( - 'provider/pool', - providerService.getProviders, - (res) => ({ [RESOURCES.document[102]]: res }) -) - -export const getProviderConnection = createAction( - 'provider', - providerService.getProviderConnection -) -export const createProvider = createAction( - 'provider/create', - providerService.createProvider -) -export const updateProvider = createAction( - 'provider/update', - providerService.updateProvider -) -export const deleteProvider = createAction( - 'provider/delete', - providerService.deleteProvider -) diff --git a/src/fireedge/src/client/features/One/provider/hooks.js b/src/fireedge/src/client/features/One/provider/hooks.js deleted file mode 100644 index 6dc5861686..0000000000 --- a/src/fireedge/src/client/features/One/provider/hooks.js +++ /dev/null @@ -1,45 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/provider/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useProvider = () => - useSelector((state) => state[name]?.[RESOURCES.document[102]]) - -export const useProviderApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getProvider: (id) => unwrapDispatch(actions.getProvider({ id })), - getProviders: () => dispatch(actions.getProviders()), - getProviderConnection: (id) => - unwrapDispatch(actions.getProviderConnection({ id })), - createProvider: (data) => unwrapDispatch(actions.createProvider({ data })), - updateProvider: (id, data) => - unwrapDispatch(actions.updateProvider({ id, data })), - deleteProvider: (id) => unwrapDispatch(actions.deleteProvider({ id })), - } -} diff --git a/src/fireedge/src/client/features/One/provider/services.js b/src/fireedge/src/client/features/One/provider/services.js deleted file mode 100644 index 657f029fc3..0000000000 --- a/src/fireedge/src/client/features/One/provider/services.js +++ /dev/null @@ -1,136 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { PROVIDER } from 'server/routes/api/oneprovision/basepath' -import { httpCodes, defaults } from 'server/utils/constants' -import { RestClient } from 'client/utils' - -const { POST, PUT, DELETE } = defaults?.httpMethod || {} - -export const providerService = { - /** - * Retrieves information for the provider. - * - * @param {object} data - Request parameters - * @param {string} data.id - Provider id - * @returns {object} Get provider identified by id - * @throws Fails when response isn't code 200 - */ - getProvider: async ({ id }) => { - const res = await RestClient.request({ - url: `/api/${PROVIDER}/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.DOCUMENT ?? {} - }, - - /** - * Retrieves information for all providers. - * - * @returns {Array} List of providers - * @throws Fails when response isn't code 200 - */ - getProviders: async () => { - const res = await RestClient.request({ - url: `/api/${PROVIDER}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat() - }, - - /** - * Retrieves connection information for the - * provider. - * - * @param {object} data - Request parameters - * @param {string} data.id - Provider id - * @returns {object} Get connection info from the - * provider identified by id - * @throws Fails when response isn't code 200 - */ - getProviderConnection: async ({ id }) => { - const res = await RestClient.request({ - url: `/api/${PROVIDER}/connection/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - - /** - * Create a provider. - * - * @param {object} params - Request parameters - * @param {object} params.data - Template data - * @returns {object} Object of document created - * @throws Fails when response isn't code 200 - */ - createProvider: async ({ data = {} }) => { - const res = await RestClient.request({ - data, - method: POST, - url: `/api/${PROVIDER}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - - /** - * Update the provider information. - * - * @param {object} params - Request parameters - * @param {object} params.id - Provider id - * @param {object} params.data - Updated data - * @returns {object} Object of document updated - * @throws Fails when response isn't code 200 - */ - updateProvider: async ({ id, data = {} }) => { - const res = await RestClient.request({ - data, - method: PUT, - url: `/api/${PROVIDER}/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - - /** - * Delete the provider. - * - * @param {object} params - Request parameters - * @param {object} params.id - Provider id - * @returns {object} Object of document deleted - * @throws Fails when response isn't code 200 - */ - deleteProvider: async ({ id }) => { - const res = await RestClient.request({ - method: DELETE, - url: `/api/${PROVIDER}/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, -} diff --git a/src/fireedge/src/client/features/One/provision/actions.js b/src/fireedge/src/client/features/One/provision/actions.js deleted file mode 100644 index 28ab06fddb..0000000000 --- a/src/fireedge/src/client/features/One/provision/actions.js +++ /dev/null @@ -1,79 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { provisionService } from 'client/features/One/provision/services' -import { RESOURCES } from 'client/features/One/slice' - -export const getProvisionsTemplates = createAction( - 'provisions-template/pool', - provisionService.getProvisionsTemplates, - (res) => ({ [RESOURCES.document.defaults]: res }) -) - -export const createProvisionTemplate = createAction( - 'provisions-template/create', - provisionService.createProvisionTemplate -) - -export const getProvision = createAction( - 'provision', - provisionService.getProvision -) - -export const getProvisions = createAction( - 'provision/pool', - provisionService.getProvisions, - (res) => ({ [RESOURCES.document[103]]: res }) -) - -export const createProvision = createAction( - 'provision/create', - provisionService.createProvision -) -export const configureProvision = createAction( - 'provision/configure', - provisionService.configureProvision -) -export const deleteProvision = createAction( - 'provision/delete', - provisionService.deleteProvision -) -export const getProvisionLog = createAction( - 'provision/log', - provisionService.getProvisionLog -) - -export const deleteDatastore = createAction( - 'provision/datastore/delete', - provisionService.deleteDatastore -) -export const deleteVNetwork = createAction( - 'provision/vnet/delete', - provisionService.deleteVNetwork -) -export const deleteHost = createAction( - 'provision/host/delete', - provisionService.deleteHost -) -export const configureHost = createAction( - 'provision/host/configure', - provisionService.configureHost -) -export const addHost = createAction( - 'provision/host/add', - provisionService.addHost -) -export const addIp = createAction('provision/ip/add', provisionService.addIp) diff --git a/src/fireedge/src/client/features/One/provision/hooks.js b/src/fireedge/src/client/features/One/provision/hooks.js deleted file mode 100644 index 3a7bdf4984..0000000000 --- a/src/fireedge/src/client/features/One/provision/hooks.js +++ /dev/null @@ -1,61 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/provision/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useProvisionTemplate = () => - useSelector((state) => state[name]?.[RESOURCES.document.defaults]) - -export const useProvision = () => - useSelector((state) => state[name]?.[RESOURCES.document[103]]) - -export const useProvisionApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getProvisionsTemplates: () => - unwrapDispatch(actions.getProvisionsTemplates()), - createProvisionTemplate: () => - unwrapDispatch(actions.createProvisionTemplate()), - - getProvision: (id) => unwrapDispatch(actions.getProvision({ id })), - getProvisions: () => dispatch(actions.getProvisions()), - createProvision: (data) => - unwrapDispatch(actions.createProvision({ data })), - configureProvision: (id) => - unwrapDispatch(actions.configureProvision({ id })), - deleteProvision: (id, data) => - unwrapDispatch(actions.deleteProvision({ id, ...data })), - getProvisionLog: (id) => unwrapDispatch(actions.getProvisionLog({ id })), - - deleteDatastore: (id) => unwrapDispatch(actions.deleteDatastore({ id })), - deleteVNetwork: (id) => unwrapDispatch(actions.deleteVNetwork({ id })), - deleteHost: (id) => unwrapDispatch(actions.deleteHost({ id })), - configureHost: (id) => unwrapDispatch(actions.configureHost({ id })), - addHost: (id, amount) => unwrapDispatch(actions.addHost({ id, amount })), - addIp: (id, amount) => unwrapDispatch(actions.addIp({ id, amount })), - } -} diff --git a/src/fireedge/src/client/features/One/provision/services.js b/src/fireedge/src/client/features/One/provision/services.js deleted file mode 100644 index e735108a82..0000000000 --- a/src/fireedge/src/client/features/One/provision/services.js +++ /dev/null @@ -1,313 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { PROVISION } from 'server/routes/api/oneprovision/basepath' -import { httpCodes, defaults } from 'server/utils/constants' -import { RestClient } from 'client/utils' - -const { POST, PUT, DELETE } = defaults?.httpMethod || {} - -export const provisionService = { - // -------------------------------------------- - // PROVISION TEMPLATE requests - // -------------------------------------------- - - /** - * Retrieves information for all the - * provision templates. - * - * @returns {Array} List of provision templates - * @throws Fails when response isn't code 200 - */ - getProvisionsTemplates: async () => { - const res = await RestClient.request({ - url: `/api/${PROVISION}/defaults`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? [] - }, - - /** - * TODO: Create a provision template. - * - * @returns {Promise} TODO - */ - createProvisionTemplate: () => - Promise.resolve().then((res) => res?.data?.DOCUMENT ?? {}), - - // -------------------------------------------- - // PROVISION requests - // -------------------------------------------- - - /** - * Retrieves information for the provision. - * - * @param {object} data - Request parameters - * @param {string} data.id - Provision id - * @returns {object} Get provision identified by id - * @throws Fails when response isn't code 200 - */ - getProvision: async ({ id }) => { - const res = await RestClient.request({ - url: `/api/${PROVISION}/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.DOCUMENT ?? {} - }, - - /** - * Retrieves information for all providers. - * - * @returns {Array} List of providers - * @throws Fails when response isn't code 200 - */ - getProvisions: async () => { - const res = await RestClient.request({ - url: `/api/${PROVISION}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat() - }, - - /** - * Create a provision. - * - * @param {object} params - Request parameters - * @param {object} params.data - Form data - * @returns {object} Object of document created - * @throws Fails when response isn't code 200 - */ - createProvision: async ({ data = {} }) => { - const res = await RestClient.request({ - data, - method: POST, - url: `/api/${PROVISION}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) { - if (res?.id === httpCodes.accepted.id) return res?.data - throw res - } - - return res?.data - }, - - /** - * Configure the provision hosts. - * - * @param {object} params - Request parameters - * @param {object} params.id - Provision id - * @returns {object} Object of document updated - * @throws Fails when response isn't code 200 - */ - configureProvision: async ({ id }) => { - const res = await RestClient.request({ - method: PUT, - url: `/api/${PROVISION}/configure/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) { - if (res?.id === httpCodes.accepted.id) return res - throw res - } - - return res?.data ?? {} - }, - - /** - * Delete the provision and OpenNebula objects. - * - * @param {object} params - Request parameters - * @param {object} params.id - Provider id - * @param {boolean} params.force - Force configure to execute - * @param {boolean} params.cleanup - * - If `true`, force to terminate VMs running - * on provisioned Hosts and delete all images in the datastores - * @returns {object} Object of document deleted - * @throws Fails when response isn't code 200 - */ - deleteProvision: async ({ id, ...data }) => { - const res = await RestClient.request({ - method: DELETE, - url: `/api/${PROVISION}/${id}`, - data, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) { - if (res?.id === httpCodes.accepted.id) return res - throw res - } - - return res?.data ?? {} - }, - - /** - * Retrieves debug log for the provision. - * - * @param {object} data - Request parameters - * @param {string} data.id - Provision id - * @returns {object} Get provision log identified by id - * @throws Fails when response isn't code 200 - */ - getProvisionLog: async ({ id }) => { - const res = await RestClient.request({ - url: `/api/${PROVISION}/log/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) { - if (res?.id === httpCodes.accepted.id) return res - throw res - } - - return res?.data ?? {} - }, - - // -------------------------------------------- - // INFRASTRUCTURE requests - // -------------------------------------------- - - /** - * Delete the datastore from the provision. - * - * @param {object} params - Request parameters - * @param {object} params.id - Datastore id - * @returns {object} Object of document deleted - * @throws Fails when response isn't code 200 - */ - deleteDatastore: async ({ id }) => { - const res = await RestClient.request({ - method: DELETE, - url: `/api/${PROVISION}/datastore/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - - /** - * Delete the virtual network from the provision. - * - * @param {object} params - Request parameters - * @param {object} params.id - Virtual network id - * @returns {object} Object of document deleted - * @throws Fails when response isn't code 200 - */ - deleteVNetwork: async ({ id }) => { - const res = await RestClient.request({ - method: DELETE, - url: `/api/${PROVISION}/network/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - - /** - * Delete the host from the provision. - * - * @param {object} params - Request parameters - * @param {object} params.id - Host id - * @returns {object} Object of document deleted - * @throws Fails when response isn't code 200 - */ - deleteHost: async ({ id }) => { - const res = await RestClient.request({ - method: DELETE, - url: `/api/${PROVISION}/host/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - - /** - * Configure the provision host. - * - * @param {object} params - Request parameters - * @param {object} params.id - Host id - * @returns {object} Object of document updated - * @throws Fails when response isn't code 200 - */ - configureHost: async ({ id }) => { - const res = await RestClient.request({ - method: PUT, - url: `/api/${PROVISION}/host/${id}`, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) { - if (res?.id === httpCodes.accepted.id) return res - throw res - } - - return res?.data ?? {} - }, - - /** - * Provisions and configures a new host or amount of hosts. - * - * @param {object} params - Request parameters - * @param {object} params.id - Provision id - * @param {object} params.amount - Amount of hosts to add to the provision - * @returns {object} Object of document updated - * @throws Fails when response isn't code 200 - */ - addHost: async ({ id, amount }) => { - const res = await RestClient.request({ - method: PUT, - url: `/api/${PROVISION}/addhost/${id}`, - data: { amount }, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) { - if (res?.id === httpCodes.accepted.id) return res - throw res - } - - return res?.data ?? {} - }, - - /** - * Adds more IPs to the provision.. - * - * @param {object} params - Request parameters - * @param {object} params.id - Provision id - * @param {object} params.amount - Amount of ips to add to the provision - * @returns {object} Object of document updated - * @throws Fails when response isn't code 200 - */ - addIp: async ({ id, amount }) => { - const res = await RestClient.request({ - method: PUT, - url: `/api/${PROVISION}/ip/${id}`, - data: { amount }, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) { - if (res?.id === httpCodes.accepted.id) return res - throw res - } - - return res?.data ?? {} - }, -} diff --git a/src/fireedge/src/client/features/One/slice.js b/src/fireedge/src/client/features/One/slice.js deleted file mode 100644 index 2443d6f31b..0000000000 --- a/src/fireedge/src/client/features/One/slice.js +++ /dev/null @@ -1,143 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createSlice, isPending, isFulfilled } from '@reduxjs/toolkit' - -import { logout } from 'client/features/Auth/actions' -import { updateResourceList } from 'client/features/One/utils' -import { eventUpdateResourceState } from 'client/features/One/socket/actions' -import { updateResourceFromFetch } from 'client/features/One/actions' - -const getNameListFromType = (type) => RESOURCES[type.split('/')[0]] - -const RESOURCES = { - acl: 'acl', - app: 'apps', - cluster: 'clusters', - datastore: 'datastores', - file: 'files', - group: 'groups', - host: 'hosts', - image: 'images', - marketplace: 'marketplaces', - secgroups: 'securityGroups', - system: 'system', - template: 'templates', - user: 'users', - vdc: 'vdc', - vm: 'vms', - vmgroup: 'vmGroups', - vn: 'vNetworks', - vntemplate: 'vNetworksTemplates', - vrouter: 'vRouters', - zone: 'zones', - document: { - 100: 'applications', - 101: 'applicationsTemplates', - 102: 'providers', - 103: 'provisions', - // extra: only for client - defaults: 'provisionsTemplates', - }, -} - -const initial = { - requests: {}, - - [RESOURCES.acl]: [], - [RESOURCES.app]: [], - [RESOURCES.cluster]: [], - [RESOURCES.datastore]: [], - [RESOURCES.file]: [], - [RESOURCES.group]: [], - [RESOURCES.host]: [], - [RESOURCES.image]: [], - [RESOURCES.marketplace]: [], - [RESOURCES.secgroups]: [], - [RESOURCES.system]: {}, - [RESOURCES.template]: [], - [RESOURCES.user]: [], - [RESOURCES.vdc]: [], - [RESOURCES.vm]: [], - [RESOURCES.vmgroup]: [], - [RESOURCES.vn]: [], - [RESOURCES.vntemplate]: [], - [RESOURCES.vrouter]: [], - [RESOURCES.zone]: [], - [RESOURCES.document[100]]: [], - [RESOURCES.document[101]]: [], - [RESOURCES.document[102]]: [], - [RESOURCES.document[103]]: [], - [RESOURCES.document.defaults]: [], -} - -const { name, actions, reducer } = createSlice({ - name: 'one', - initialState: initial, - extraReducers: (builder) => { - builder - .addMatcher( - ({ type }) => type === logout.type, - () => initial - ) - .addMatcher( - ({ type }) => - type.startsWith(RESOURCES.system) && type.endsWith('/fulfilled'), - (state, { payload }) => ({ ...state, ...payload }) - ) - .addMatcher( - ({ type }) => - type === updateResourceFromFetch.type || - (type.endsWith('/fulfilled') && - (type.includes(eventUpdateResourceState.typePrefix) || - type.includes('/detail'))), - (state, { payload, type }) => { - // TYPE and DATA can be force by payload - const listName = getNameListFromType(payload?.type ?? type) - - const newList = updateResourceList( - state[listName], - payload?.data ?? payload - ) - - return { ...state, [listName]: newList } - } - ) - .addMatcher( - ({ type }) => type.includes('/pool'), - (state, action) => { - const { requests } = state - const { payload, type } = action - - // filter type without: /pending, /fulfilled or /rejected - const pureType = type.match(/(.*\/pool)/)[0] - - if (isPending(action)) { - return { ...state, requests: { ...requests, [pureType]: action } } - } - - const { [pureType]: _, ...restOfRequests } = requests - - return { - ...state, - ...(isFulfilled(action) && payload), - requests: restOfRequests, - } - } - ) - }, -}) - -export { name, actions, reducer, RESOURCES } diff --git a/src/fireedge/src/client/features/One/socket/actions.js b/src/fireedge/src/client/features/One/socket/actions.js deleted file mode 100644 index f373707a9a..0000000000 --- a/src/fireedge/src/client/features/One/socket/actions.js +++ /dev/null @@ -1,141 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAsyncThunk } from '@reduxjs/toolkit' - -import * as actions from 'client/features/General/actions' -import { RESOURCES } from 'client/features/One/slice' -import { HookStateData, HookApiData } from 'client/features/One/socket/types' -import { generateKey } from 'client/utils' - -const MESSAGE_PROVISION_SUCCESS_CREATED = 'Provision successfully created' - -const COMMANDS = { - create: 'create', - update: 'update', - delete: 'delete', -} - -/** - * @param {HookStateData} data - Event data from hook event STATE - * @returns {{name: ('vm'|'host'|'image'), value: object}} - * - Name and new value of resource - */ -export const getResourceFromEventState = (data) => { - const { HOOK_OBJECT: name, [name]: value } = data?.HOOK_MESSAGE ?? {} - - return { name: String(name).toLowerCase(), value } -} - -/** - * @param {HookApiData} data - Event data from hook event API - * @returns {{ - * action: string, - * name: string, - * value: object, - * success: boolean, - * output: object - * }} - Resource information from event Api - */ -export const getResourceFromEventApi = (data = {}) => { - const { CALL: command = '', CALL_INFO: info = {} } = data?.HOOK_MESSAGE - const { EXTRA: extra, RESULT: result, PARAMETERS } = info - - // command: 'one.resourceName.action' - const [, resourceName, action] = command.split('.') - - const success = result === '1' - - const value = extra?.[String(resourceName).toUpperCase()] - - const resource = RESOURCES[resourceName] - const name = resource?.[value?.TYPE] ?? resource - - const [, { VALUE: output }] = PARAMETERS?.PARAMETER?.filter( - ({ TYPE }) => TYPE === 'OUT' - ) - - return { action, name, value, success, output } -} - -/** - * The API hooks are triggered after the execution of an API call. - */ -export const eventApi = createAsyncThunk( - 'socket/event-api', - ({ data } = {}) => { - const { action, name, value, success } = getResourceFromEventApi(data) - - // console.log({ action, name, value, success, output }) - - return success && value && action !== COMMANDS.delete - ? { [name]: value } - : {} - }, - { - condition: ({ data } = {}) => data?.HOOK_MESSAGE?.HOOK_TYPE === 'API', - } -) - -/** - * Dispatch new resource object when OpenNebula hooks is triggered - * on specific state transition. - * - * Supported values: `HOST`, `VM`, `IMAGE` - */ -export const eventUpdateResourceState = createAsyncThunk( - 'socket/event-state', - (data = {}) => { - const { name, value } = getResourceFromEventState(data) - - return { type: name, data: value } - }, - { - condition: (data = {}) => { - const { name, value } = getResourceFromEventState(data) - - return ( - data?.HOOK_MESSAGE?.HOOK_TYPE === 'STATE' && - // possible hook objects: VM, IMAGE, HOST - ['vm', 'host', 'image'].includes(name) && - // update the list if event returns resource value - value !== '' - ) - }, - } -) - -/** - * Dispatch successfully notification when one provision is created - */ -export const onCreateProvision = createAsyncThunk( - 'socket/create-provision', - (_, { dispatch }) => { - dispatch( - actions.enqueueSnackbar({ - key: generateKey(), - message: MESSAGE_PROVISION_SUCCESS_CREATED, - options: { variant: 'success' }, - }) - ) - }, - { - condition: (payload = {}) => { - const { command, data } = payload - - return command === 'create' && data === MESSAGE_PROVISION_SUCCESS_CREATED - }, - } -) diff --git a/src/fireedge/src/client/features/One/socket/types.js b/src/fireedge/src/client/features/One/socket/types.js deleted file mode 100644 index ac1e6d11ab..0000000000 --- a/src/fireedge/src/client/features/One/socket/types.js +++ /dev/null @@ -1,62 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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. * - * ------------------------------------------------------------------------- */ - -/** - * @typedef {object} HookStateData - Event data from hook event STATE - * @property {HookStateMessage} HOOK_MESSAGE - Hook message from OpenNebula API - */ - -/** - * @typedef {object} HookStateMessage - Hook message from OpenNebula API - * @property {'STATE'} HOOK_TYPE - Type of event API - * @property {('VM'|'HOST'|'IMAGE')} HOOK_OBJECT - Type name of the resource - * @property {string} STATE - The state that triggers the hook. - * @property {string} [LCM_STATE] - * - The LCM state that triggers the hook (Only for VM hooks) - * @property {string} [REMOTE_HOST] - * - If ``yes`` the hook will be executed in the host that triggered - * the hook (for Host hooks) or in the host where the VM is running (for VM hooks). - * Not used for Image hooks. - * @property {string} RESOURCE_ID - ID of resource - * @property {object} [VM] - New data of the VM - * @property {object} [HOST] - New data of the HOST - * @property {object} [IMAGE] - New data of the IMAGE - */ - -/** - * @typedef {object} HookApiData - Event data from hook event API - * @property {HookApiMessage} HOOK_MESSAGE - Hook message from OpenNebula API - */ - -/** - * Call parameter. - * - * @typedef {object} Parameter - * @property {number} POSITION - Parameter position in the list - * @property {('IN'|'OUT')} TYPE - Parameter type - * @property {string} VALUE - Parameter value as string - */ - -/** - * @typedef {object} HookApiMessage - Event data from hook event API - * @property {'API'} HOOK_TYPE - Type of event API - * @property {string} CALL - Action name: 'one.resourceName.action' - * @property {object} [CALL_INFO] - Information about result of action - * @property {0|1} CALL_INFO.RESULT - `1` for success and `0` for error result - * @property {Parameter[]|Parameter} [CALL_INFO.PARAMETERS] - * - The list of IN and OUT parameters will match the API call parameters - * @property {object} [CALL_INFO.EXTRA] - Extra information returned for API Hooks - */ diff --git a/src/fireedge/src/client/features/One/system/actions.js b/src/fireedge/src/client/features/One/system/actions.js deleted file mode 100644 index ec43ce0bda..0000000000 --- a/src/fireedge/src/client/features/One/system/actions.js +++ /dev/null @@ -1,43 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { systemService } from 'client/features/One/system/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.system} */ -const SYSTEM = 'system' - -export const getOneVersion = createAction( - `${SYSTEM}/one-version`, - systemService.getOneVersion, - (response, one) => ({ - [RESOURCES.system]: { - ...one[RESOURCES.system], - version: response, - }, - }) -) - -export const getOneConfig = createAction( - `${SYSTEM}/one-config`, - systemService.getOneConfig, - (response, one) => ({ - [RESOURCES.system]: { - ...one[RESOURCES.system], - config: response, - }, - }) -) diff --git a/src/fireedge/src/client/features/One/system/hooks.js b/src/fireedge/src/client/features/One/system/hooks.js deleted file mode 100644 index edaf142b6d..0000000000 --- a/src/fireedge/src/client/features/One/system/hooks.js +++ /dev/null @@ -1,47 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/system/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useSystem = () => - useSelector((state) => state[name]?.[RESOURCES.system] ?? []) - -export const useSystemApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - async (action) => { - try { - const response = await dispatch(action) - - return unwrapResult(response) - } catch (error) { - return error - } - }, - [dispatch] - ) - - return { - getOneVersion: () => unwrapDispatch(actions.getOneVersion()), - getOneConfig: () => unwrapDispatch(actions.getOneConfig()), - } -} diff --git a/src/fireedge/src/client/features/One/system/services.js b/src/fireedge/src/client/features/One/system/services.js deleted file mode 100644 index 43376450e7..0000000000 --- a/src/fireedge/src/client/features/One/system/services.js +++ /dev/null @@ -1,56 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/system' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const systemService = { - /** - * Returns the OpenNebula core version. - * - * @returns {object} The OpenNebula version - * @throws Fails when response isn't code 200 - */ - getOneVersion: async () => { - const name = Actions.SYSTEM_VERSION - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Returns the OpenNebula configuration. - * - * @returns {object} The loaded oned.conf file - * @throws Fails when response isn't code 200 - */ - getOneConfig: async () => { - const name = Actions.SYSTEM_CONFIG - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, -} diff --git a/src/fireedge/src/client/features/One/user/actions.js b/src/fireedge/src/client/features/One/user/actions.js deleted file mode 100644 index 212dcccbbf..0000000000 --- a/src/fireedge/src/client/features/One/user/actions.js +++ /dev/null @@ -1,35 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { userService } from 'client/features/One/user/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.user} */ -const USER = 'user' - -export const getUser = createAction(`${USER}/detail`, userService.getUser) - -export const getUsers = createAction( - `${USER}/pool`, - userService.getUsers, - (response) => ({ [RESOURCES.user]: response }) -) - -export const updateUser = createAction(`${USER}/update`, userService.updateUser) -export const changeGroup = createAction( - `${USER}/change-group`, - userService.changeGroup -) diff --git a/src/fireedge/src/client/features/One/user/hooks.js b/src/fireedge/src/client/features/One/user/hooks.js deleted file mode 100644 index 01335ab06b..0000000000 --- a/src/fireedge/src/client/features/One/user/hooks.js +++ /dev/null @@ -1,42 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/user/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useUser = () => - useSelector((state) => state[name]?.[RESOURCES.user] ?? []) - -export const useUserApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getUser: (id) => unwrapDispatch(actions.getUser({ id })), - getUsers: () => unwrapDispatch(actions.getUsers()), - changeGroup: (data) => unwrapDispatch(actions.changeGroup(data)), - updateUser: (id, data) => - unwrapDispatch(actions.updateUser({ id, ...data })), - } -} diff --git a/src/fireedge/src/client/features/One/user/services.js b/src/fireedge/src/client/features/One/user/services.js deleted file mode 100644 index 7f414f1960..0000000000 --- a/src/fireedge/src/client/features/One/user/services.js +++ /dev/null @@ -1,103 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/user' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const userService = { - /** - * Retrieves information for the user. - * - * @param {object} data - Request parameters - * @param {string} data.id - User id - * @returns {object} Get user identified by id - * @throws Fails when response isn't code 200 - */ - getUser: async ({ id }) => { - const name = Actions.USER_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.USER ?? {} - }, - - /** - * Retrieves information for all the users in the pool. - * - * @returns {Array} List of users - * @throws Fails when response isn't code 200 - */ - getUsers: async () => { - const name = Actions.USER_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.USER_POOL?.USER ?? []].flat() - }, - - /** - * Changes the group of the given user. - * - * @param {object} params - Request parameters - * @param {object} params.data - Form data - * @returns {number} User id - * @throws Fails when response isn't code 200 - */ - changeGroup: async (params) => { - const name = Actions.USER_CHGRP - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, - - /** - * Replaces the user template contents. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - User id - * @param {string} params.template - The new user template contents - * @param {0|1} params.replace - * - Update type: - * ``0``: Replace the whole template. - * ``1``: Merge new template with the existing one. - * @returns {number} User id - * @throws Fails when response isn't code 200 - */ - updateUser: async (params) => { - const name = Actions.USER_UPDATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data ?? {} - }, -} diff --git a/src/fireedge/src/client/features/One/utils.js b/src/fireedge/src/client/features/One/utils.js deleted file mode 100644 index 05c1ad3d34..0000000000 --- a/src/fireedge/src/client/features/One/utils.js +++ /dev/null @@ -1,77 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAsyncThunk, AsyncThunkAction } from '@reduxjs/toolkit' - -import { logout } from 'client/features/Auth/actions' - -import { T } from 'client/constants' -import { httpCodes } from 'server/utils/constants' - -/** - * @param {string} type - Name of redux action - * @param {Promise} service - Request from service - * @param {function(object, object)} [wrapResult] - Function to wrapping the response - * @returns {AsyncThunkAction} Asynchronous redux action - */ -export const createAction = (type, service, wrapResult) => - createAsyncThunk( - type, - async (payload, { dispatch, getState, rejectWithValue }) => { - try { - const { - auth: { filterPool }, - one, - } = getState() - - const response = await service({ - ...payload, - filter: filterPool, - }) - - return wrapResult?.(response, one) ?? response - } catch (error) { - const { message, data, status, statusText } = error - - status === httpCodes.unauthorized.id && - dispatch(logout(T.SessionExpired)) - - return rejectWithValue( - message ?? data?.data ?? data?.message ?? statusText - ) - } - }, - { - condition: (_, { getState }) => !getState().one.requests[type], - } - ) - -/** - * @param {object} currentList - Current list of resources from redux - * @param {object} value - OpenNebula resource - * @returns {Array} Returns a new list with the attributes editable modified - */ -export const updateResourceList = (currentList, value) => { - const id = value.ID - - const currentItem = currentList?.find(({ ID }) => ID === id) - - // update if exists in current list, if not add it to list - const updatedList = currentItem - ? currentList?.map((item) => (item?.ID === id ? value : item)) - : [value, ...currentList] - - return updatedList -} diff --git a/src/fireedge/src/client/features/One/vm/actions.js b/src/fireedge/src/client/features/One/vm/actions.js deleted file mode 100644 index ea841737b1..0000000000 --- a/src/fireedge/src/client/features/One/vm/actions.js +++ /dev/null @@ -1,163 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { vmService } from 'client/features/One/vm/services' -import { filterBy } from 'client/utils' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.vm} */ -const VM = 'vm' - -export const getVm = createAction(`${VM}/detail`, vmService.getVm) - -export const getVms = createAction( - `${VM}/pool`, - vmService.getVms, - (response, { [RESOURCES.vm]: currentVms }) => { - const vms = filterBy([...currentVms, ...response], 'ID') - - return { [RESOURCES.vm]: vms } - } -) - -export const terminate = createAction(`${VM}/terminate`, ({ id }) => - vmService.actionVm({ id, action: 'terminate' }) -) -export const terminateHard = createAction(`${VM}/terminate-hard`, ({ id }) => - vmService.actionVm({ id, action: 'terminate-hard' }) -) -export const undeploy = createAction(`${VM}/undeploy`, ({ id }) => - vmService.actionVm({ id, action: 'undeploy' }) -) -export const undeployHard = createAction(`${VM}/undeploy-hard`, ({ id }) => - vmService.actionVm({ id, action: 'undeploy-hard' }) -) -export const poweroff = createAction(`${VM}/poweroff`, ({ id }) => - vmService.actionVm({ id, action: 'poweroff' }) -) -export const poweroffHard = createAction(`${VM}/poweroff-hard`, ({ id }) => - vmService.actionVm({ id, action: 'poweroff-hard' }) -) -export const reboot = createAction(`${VM}/reboot`, ({ id }) => - vmService.actionVm({ id, action: 'reboot' }) -) -export const rebootHard = createAction(`${VM}/reboot-hard`, ({ id }) => - vmService.actionVm({ id, action: 'reboot-hard' }) -) -export const hold = createAction(`${VM}/hold`, ({ id }) => - vmService.actionVm({ id, action: 'hold' }) -) -export const release = createAction(`${VM}/release`, ({ id }) => - vmService.actionVm({ id, action: 'release' }) -) -export const stop = createAction(`${VM}/stop`, ({ id }) => - vmService.actionVm({ id, action: 'stop' }) -) -export const suspend = createAction(`${VM}/suspend`, ({ id }) => - vmService.actionVm({ id, action: 'suspend' }) -) -export const resume = createAction(`${VM}/resume`, ({ id }) => - vmService.actionVm({ id, action: 'resume' }) -) -export const resched = createAction(`${VM}/resched`, ({ id }) => - vmService.actionVm({ id, action: 'resched' }) -) -export const unresched = createAction(`${VM}/unresched`, ({ id }) => - vmService.actionVm({ id, action: 'unresched' }) -) - -export const updateUserTemplate = createAction( - `${VM}/update`, - vmService.updateUserTemplate -) -export const rename = createAction(`${VM}/rename`, vmService.rename) -export const resize = createAction(`${VM}/resize`, vmService.resize) -export const changePermissions = createAction( - `${VM}/chmod`, - vmService.changePermissions -) -export const changeOwnership = createAction( - `${VM}/chown`, - vmService.changeOwnership -) -export const attachDisk = createAction( - `${VM}/attach/disk`, - vmService.attachDisk -) -export const detachDisk = createAction( - `${VM}/detach/disk`, - vmService.detachDisk -) -export const saveAsDisk = createAction( - `${VM}/saveas/disk`, - vmService.saveAsDisk -) -export const saveAsTemplate = createAction( - `${VM}/saveas/template`, - vmService.saveAsTemplate -) -export const resizeDisk = createAction( - `${VM}/resize/disk`, - vmService.resizeDisk -) -export const createDiskSnapshot = createAction( - `${VM}/create/disk-snapshot`, - vmService.createDiskSnapshot -) -export const renameDiskSnapshot = createAction( - `${VM}/rename/disk-snapshot`, - vmService.renameDiskSnapshot -) -export const revertDiskSnapshot = createAction( - `${VM}/revert/disk-snapshot`, - vmService.revertDiskSnapshot -) -export const deleteDiskSnapshot = createAction( - `${VM}/delete/disk-snapshot`, - vmService.deleteDiskSnapshot -) -export const attachNic = createAction(`${VM}/attach/nic`, vmService.attachNic) -export const detachNic = createAction(`${VM}/detach/nic`, vmService.detachNic) -export const createSnapshot = createAction( - `${VM}/create/snapshot`, - vmService.createSnapshot -) -export const revertSnapshot = createAction( - `${VM}/revert/snapshot`, - vmService.revertSnapshot -) -export const deleteSnapshot = createAction( - `${VM}/delete/snapshot`, - vmService.deleteSnapshot -) -export const addScheduledAction = createAction( - `${VM}/add/scheduled-action`, - vmService.addScheduledAction -) -export const updateScheduledAction = createAction( - `${VM}/update/scheduled-action`, - vmService.updateScheduledAction -) -export const deleteScheduledAction = createAction( - `${VM}/delete/scheduled-action`, - vmService.deleteScheduledAction -) -export const recover = createAction(`${VM}/recover`, vmService.recover) -export const lock = createAction(`${VM}/lock`, vmService.lock) -export const unlock = createAction(`${VM}/unlock`, vmService.unlock) -export const deploy = createAction(`${VM}/deploy`, vmService.deploy) -export const migrate = createAction(`${VM}/migrate`, vmService.migrate) -export const migrateLive = createAction(`${VM}/migrate-live`, vmService.migrate) diff --git a/src/fireedge/src/client/features/One/vm/hooks.js b/src/fireedge/src/client/features/One/vm/hooks.js deleted file mode 100644 index 149de6f4dc..0000000000 --- a/src/fireedge/src/client/features/One/vm/hooks.js +++ /dev/null @@ -1,104 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/vm/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useVm = () => - useSelector((state) => state[name]?.[RESOURCES.vm] ?? []) - -export const useVmApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getVm: (id) => unwrapDispatch(actions.getVm({ id })), - getVms: (options) => unwrapDispatch(actions.getVms(options)), - terminate: (id) => unwrapDispatch(actions.terminate({ id })), - terminateHard: (id) => unwrapDispatch(actions.terminateHard({ id })), - undeploy: (id) => unwrapDispatch(actions.undeploy({ id })), - undeployHard: (id) => unwrapDispatch(actions.undeployHard({ id })), - poweroff: (id) => unwrapDispatch(actions.poweroff({ id })), - poweroffHard: (id) => unwrapDispatch(actions.poweroffHard({ id })), - reboot: (id) => unwrapDispatch(actions.reboot({ id })), - rebootHard: (id) => unwrapDispatch(actions.rebootHard({ id })), - hold: (id) => unwrapDispatch(actions.hold({ id })), - release: (id) => unwrapDispatch(actions.release({ id })), - stop: (id) => unwrapDispatch(actions.stop({ id })), - suspend: (id) => unwrapDispatch(actions.suspend({ id })), - resume: (id) => unwrapDispatch(actions.resume({ id })), - resched: (id) => unwrapDispatch(actions.resched({ id })), - unresched: (id) => unwrapDispatch(actions.unresched({ id })), - updateUserTemplate: (id, template, replace) => - unwrapDispatch(actions.updateUserTemplate({ id, template, replace })), - rename: (id, newName) => - unwrapDispatch(actions.rename({ id, name: newName })), - resize: (id, data) => unwrapDispatch(actions.resize({ id, ...data })), - changePermissions: (id, permissions) => - unwrapDispatch(actions.changePermissions({ id, permissions })), - changeOwnership: (id, ownership) => - unwrapDispatch(actions.changeOwnership({ id, ownership })), - attachDisk: (id, template) => - unwrapDispatch(actions.attachDisk({ id, template })), - detachDisk: (id, disk) => unwrapDispatch(actions.detachDisk({ id, disk })), - saveAsDisk: (id, data) => - unwrapDispatch(actions.saveAsDisk({ id, ...data })), - saveAsTemplate: (id, data) => - unwrapDispatch(actions.saveAsTemplate({ id, ...data })), - resizeDisk: (id, data) => - unwrapDispatch(actions.resizeDisk({ id, ...data })), - createDiskSnapshot: (id, data) => - unwrapDispatch(actions.createDiskSnapshot({ id, ...data })), - renameDiskSnapshot: (id, data) => - unwrapDispatch(actions.renameDiskSnapshot({ id, ...data })), - revertDiskSnapshot: (id, data) => - unwrapDispatch(actions.revertDiskSnapshot({ id, ...data })), - deleteDiskSnapshot: (id, data) => - unwrapDispatch(actions.deleteDiskSnapshot({ id, ...data })), - attachNic: (id, template) => - unwrapDispatch(actions.attachNic({ id, template })), - detachNic: (id, nic) => unwrapDispatch(actions.detachNic({ id, nic })), - createSnapshot: (id, data) => - unwrapDispatch(actions.createSnapshot({ id, ...data })), - revertSnapshot: (id, snapshot) => - unwrapDispatch(actions.revertSnapshot({ id, snapshot })), - deleteSnapshot: (id, snapshot) => - unwrapDispatch(actions.deleteSnapshot({ id, snapshot })), - addScheduledAction: (id, data) => - unwrapDispatch(actions.addScheduledAction({ id, ...data })), - updateScheduledAction: (id, data) => - unwrapDispatch(actions.updateScheduledAction({ id, ...data })), - deleteScheduledAction: (id, data) => - unwrapDispatch(actions.deleteScheduledAction({ id, ...data })), - recover: (id, operation) => - unwrapDispatch(actions.recover({ id, operation })), - lock: (id, data) => unwrapDispatch(actions.lock({ id, ...data })), - unlock: (id) => unwrapDispatch(actions.unlock({ id })), - deploy: (id, data) => unwrapDispatch(actions.deploy({ id, ...data })), - migrate: (id, data) => - unwrapDispatch(actions.migrate({ id, ...data, live: false })), - migrateLive: (id, data) => - unwrapDispatch(actions.migrate({ id, ...data, live: true })), - } -} diff --git a/src/fireedge/src/client/features/One/vm/services.js b/src/fireedge/src/client/features/One/vm/services.js deleted file mode 100644 index ca6451a2fa..0000000000 --- a/src/fireedge/src/client/features/One/vm/services.js +++ /dev/null @@ -1,722 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vm' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const vmService = { - /** - * Retrieves information for the virtual machine. - * - * @param {object} params - Request parameters - * @param {string} params.id - User id - * @returns {object} Get user identified by id - * @throws Fails when response isn't code 200 - */ - getVm: async (params) => { - const name = Actions.VM_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.VM ?? {} - }, - - /** - * Retrieves information for all or part of - * the VMs in the pool. - * - * @param {object} params - Request parameters - * @param {string} params.filter - Filter flag - * @param {number} params.start - Range start ID - * @param {number} params.end - Range end ID - * @param {string|number} params.state - Filter state - * @returns {Array} List of VMs - * @throws Fails when response isn't code 200 - */ - getVms: async (params) => { - const name = Actions.VM_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.VM_POOL?.VM ?? []].flat() - }, - - /** - * Submits an action to be performed on a virtual machine. - * - * @param {object} params - Request parameters - * @param {string} params.id - Virtual machine id - * @param {( - * 'terminate-hard'| - * 'terminate'| - * 'undeploy-hard'| - * 'undeploy'| - * 'poweroff-hard'| - * 'poweroff'| - * 'reboot-hard'| - * 'reboot'| - * 'hold'| - * 'release'| - * 'stop'| - * 'suspend'| - * 'resume'| - * 'resched'| - * 'unresched' - * )} params.action - The action name to be performed - * @returns {Response} Response - * @throws Fails when response isn't code 200 - */ - actionVm: async (params) => { - const name = Actions.VM_ACTION - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.VM ?? {} - }, - - /** - * Clones the VM's source Template, replacing the disks with live snapshots - * of the current disks. The VM capacity and NICs are also preserved. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.name - Template name - * @param {boolean} params.persistent - Make the new images persistent - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - saveAsTemplate: async ({ id, name, persistent }) => { - const res = await RestClient.request({ - url: `/api/vm/save/${id}`, - method: 'POST', - data: { name, persistent }, - }) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Renames a virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.name - New name - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - rename: async (params) => { - const name = Actions.VM_RENAME - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Changes the capacity of the virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.template - Template containing the new capacity - * @param {boolean} params.enforce - * - `true` to enforce the Host capacity isn't over committed. - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - resize: async (params) => { - const name = Actions.VM_RESIZE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Replaces the user template contents. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.template - The new user template contents - * @param {0|1} params.replace - * - Update type: - * ``0``: Replace the whole template. - * ``1``: Merge new template with the existing one. - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - updateUserTemplate: async (params) => { - const name = Actions.VM_UPDATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Changes the permission bits of a virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {{ - * ownerUse: number, - * ownerManage: number, - * ownerAdmin: number, - * groupUse: number, - * groupManage: number, - * groupAdmin: number, - * otherUse: number, - * otherManage: number, - * otherAdmin: number - * }} params.permissions - Permissions data - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - changePermissions: async ({ id, permissions }) => { - const name = Actions.VM_CHMOD - const command = { name, ...Commands[name] } - const config = requestConfig({ id, ...permissions }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Changes the ownership bits of a virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {{user: number, group: number}} params.ownership - Ownership data - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - changeOwnership: async ({ id, ownership }) => { - const name = Actions.VM_CHOWN - const command = { name, ...Commands[name] } - const config = requestConfig({ id, ...ownership }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Attaches a new disk to the virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.template - * - A string containing a single DISK vector attribute - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - attachDisk: async (params) => { - const name = Actions.VM_DISK_ATTACH - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Detaches a disk from a virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.disk - Disk id - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - detachDisk: async (params) => { - const name = Actions.VM_DISK_DETACH - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Sets the disk to be saved in the given image. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.disk - Disk id - * @param {string} params.name - Name for the new Image - * @param {string} params.type - Type for the new Image. - * If it is an empty string, then the default one will be used - * @param {string|number} params.snapshot - Id of the snapshot to export. - * If -1 the current image state will be used. - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - saveAsDisk: async (params) => { - const name = Actions.VM_DISK_SAVEAS - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Resizes a disk of a virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.disk - Disk id - * @param {string} params.size - The new size string - * - Options to perform action - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - resizeDisk: async (params) => { - const name = Actions.VM_DISK_RESIZE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Takes a new snapshot of the disk image. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.disk - Disk id - * @param {string} params.description - Description for the snapshot - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - createDiskSnapshot: async (params) => { - const name = Actions.VM_DISK_SNAP_CREATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Renames a disk snapshot. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.disk - Disk id - * @param {string|number} params.snapshot - Snapshot id - * @param {string} params.name - New snapshot name - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - renameDiskSnapshot: async (params) => { - const name = Actions.VM_DISK_SNAP_RENAME - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Reverts disk state to a previously taken snapshot. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.disk - Disk id - * @param {string|number} params.snapshot - Snapshot id - * @returns {number} The snapshot id used - * @throws Fails when response isn't code 200 - */ - revertDiskSnapshot: async (params) => { - const name = Actions.VM_DISK_SNAP_REVERT - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Deletes a disk snapshot. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.disk - Disk id - * @param {string|number} params.snapshot - Snapshot id - * @returns {number} The id of the snapshot deleted - * @throws Fails when response isn't code 200 - */ - deleteDiskSnapshot: async (params) => { - const name = Actions.VM_DISK_SNAP_DELETE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Attaches a new network interface to the virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.template - * - A string containing a single NIC vector attribute - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - attachNic: async (params) => { - const name = Actions.VM_NIC_ATTACH - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Detaches a network interface from a virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.nic - NIC id - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - detachNic: async (params) => { - const name = Actions.VM_NIC_DETACH - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Creates a new virtual machine snapshot. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.name - The new snapshot name - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - createSnapshot: async (params) => { - const name = Actions.VM_SNAP_CREATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Reverts a virtual machine to a snapshot. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.snapshot - The snapshot id - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - revertSnapshot: async (params) => { - const name = Actions.VM_SNAP_REVERT - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Deletes a virtual machine snapshot. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.snapshot - The snapshot id - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - deleteSnapshot: async (params) => { - const name = Actions.VM_SNAP_DELETE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Add scheduled action to VM. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.template - Template containing the new scheduled action - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - addScheduledAction: async (params) => { - const name = Actions.VM_SCHED_ADD - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Update scheduled VM action. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.id_sched - The ID of the scheduled action - * @param {string} params.template - Template containing the updated scheduled action - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - updateScheduledAction: async (params) => { - const name = Actions.VM_SCHED_UPDATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Delete scheduled action from VM. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string} params.id_sched - The ID of the scheduled action - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - deleteScheduledAction: async (params) => { - const name = Actions.VM_SCHED_DELETE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Recovers a stuck VM that is waiting for a driver operation. - * The recovery may be done by failing or succeeding the pending operation. - * - * You need to manually check the vm status on the host, to decide - * if the operation was successful or not. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {0|1|2|3|4} params.operation - Recover operation: - * success (1), failure (0), retry (2), delete (3), delete-recreate (4) - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - recover: async (params) => { - const name = Actions.VM_RECOVER - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Locks a virtual machine. Lock certain actions depending on blocking level. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {1|2|3|4} params.level - * - Lock level: - * ``1``: Use - * ``2``: Manage - * ``3``: Admin - * ``4``: All - * @param {boolean} params.test - Check if the object is already locked to return an error - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - lock: async (params) => { - const name = Actions.VM_LOCK - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Unlocks a virtual machine. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - unlock: async (params) => { - const name = Actions.VM_UNLOCK - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Initiates the instance of the given VM id on the target host. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.host - The target host id - * @param {boolean} params.enforce - * - If `true`, will enforce the Host capacity isn't over committed. - * @param {string|number} params.datastore - The target datastore id. - * It is optional, and can be set to -1 to let OpenNebula choose the datastore - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - deploy: async (params) => { - const name = Actions.VM_DEPLOY - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Migrates one virtual machine to the target host. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Virtual machine id - * @param {string|number} params.host - The target host id - * @param {boolean} params.live - * - If `true` we are indicating that we want live migration, otherwise `false`. - * @param {boolean} params.enforce - * - If `true`, will enforce the Host capacity isn't over committed. - * @param {string|number} params.datastore - The target datastore id. - * It is optional, and can be set to -1 to let OpenNebula choose the datastore - * @param {0|1|2} params.type - Migration type: save (0), poweroff (1), poweroff-hard (2) - * @returns {number} Virtual machine id - * @throws Fails when response isn't code 200 - */ - migrate: async (params) => { - const name = Actions.VM_MIGRATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, -} diff --git a/src/fireedge/src/client/features/One/vmGroup/actions.js b/src/fireedge/src/client/features/One/vmGroup/actions.js deleted file mode 100644 index 99ec6d4d5e..0000000000 --- a/src/fireedge/src/client/features/One/vmGroup/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { vmGroupService } from 'client/features/One/vmGroup/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.vmgroup} */ -const VM_GROUP = 'vmgroup' - -export const getVmGroup = createAction( - `${VM_GROUP}/detail`, - vmGroupService.getVmGroup -) - -export const getVmGroups = createAction( - `${VM_GROUP}/pool`, - vmGroupService.getVmGroups, - (response) => ({ [RESOURCES.vmgroup]: response }) -) diff --git a/src/fireedge/src/client/features/One/vmGroup/hooks.js b/src/fireedge/src/client/features/One/vmGroup/hooks.js deleted file mode 100644 index 8b5394516e..0000000000 --- a/src/fireedge/src/client/features/One/vmGroup/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/vmGroup/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useVmGroup = () => - useSelector((state) => state[name]?.[RESOURCES.vmgroup]) - -export const useVmGroupApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getVmGroup: (id) => unwrapDispatch(actions.getVmGroup({ id })), - getVmGroups: () => unwrapDispatch(actions.getVmGroups()), - } -} diff --git a/src/fireedge/src/client/features/One/vmGroup/services.js b/src/fireedge/src/client/features/One/vmGroup/services.js deleted file mode 100644 index b2bf19bb3d..0000000000 --- a/src/fireedge/src/client/features/One/vmGroup/services.js +++ /dev/null @@ -1,64 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vmgroup' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const vmGroupService = { - /** - * Retrieves information for the VM group. - * - * @param {object} params - Request parameters - * @param {string} params.id - VM group id - * @param {boolean} params.decrypt - `true` to decrypt contained secrets - * @returns {object} Get VM group identified by id - * @throws Fails when response isn't code 200 - */ - getVmGroup: async (params) => { - const name = Actions.VM_GROUP_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.VM_GROUP ?? {} - }, - - /** - * Retrieves information for all or part of the - * VM groups in the pool. - * - * @param {object} data - Request params - * @param {string} data.filter - Filter flag - * @param {number} data.start - Range start ID - * @param {number} data.end - Range end ID - * @returns {Array} List of VM groups - * @throws Fails when response isn't code 200 - */ - getVmGroups: async ({ filter, start, end }) => { - const name = Actions.VM_GROUP_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ filter, start, end }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.VM_GROUP_POOL?.VM_GROUP ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/vmTemplate/actions.js b/src/fireedge/src/client/features/One/vmTemplate/actions.js deleted file mode 100644 index 7bb29d6a46..0000000000 --- a/src/fireedge/src/client/features/One/vmTemplate/actions.js +++ /dev/null @@ -1,67 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { vmTemplateService } from 'client/features/One/vmTemplate/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.template} */ -const TEMPLATE = 'template' - -export const getVmTemplate = createAction( - `${TEMPLATE}/detail`, - vmTemplateService.getVmTemplate -) - -export const getVmTemplates = createAction( - `${TEMPLATE}/pool`, - vmTemplateService.getVmTemplates, - (response) => ({ [RESOURCES.template]: response }) -) - -export const instantiate = createAction( - `${TEMPLATE}/instantiate`, - vmTemplateService.instantiate -) -export const allocate = createAction( - `${TEMPLATE}/allocate`, - vmTemplateService.allocate -) -export const clone = createAction(`${TEMPLATE}/clone`, vmTemplateService.clone) -export const remove = createAction( - `${TEMPLATE}/delete`, - vmTemplateService.delete -) -export const update = createAction( - `${TEMPLATE}/update`, - vmTemplateService.update -) -export const changePermissions = createAction( - `${TEMPLATE}/chmod`, - vmTemplateService.changePermissions -) -export const changeOwnership = createAction( - `${TEMPLATE}/chown`, - vmTemplateService.changeOwnership -) -export const rename = createAction( - `${TEMPLATE}/rename`, - vmTemplateService.rename -) -export const lock = createAction(`${TEMPLATE}/lock`, vmTemplateService.lock) -export const unlock = createAction( - `${TEMPLATE}/unlock`, - vmTemplateService.unlock -) diff --git a/src/fireedge/src/client/features/One/vmTemplate/hooks.js b/src/fireedge/src/client/features/One/vmTemplate/hooks.js deleted file mode 100644 index 975598b893..0000000000 --- a/src/fireedge/src/client/features/One/vmTemplate/hooks.js +++ /dev/null @@ -1,55 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/vmTemplate/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useVmTemplate = () => - useSelector((state) => state[name]?.[RESOURCES.template] ?? []) - -export const useVmTemplateApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getVmTemplate: (id, data) => - unwrapDispatch(actions.getVmTemplate({ id, ...data })), - getVmTemplates: () => unwrapDispatch(actions.getVmTemplates()), - instantiate: (id, data) => - unwrapDispatch(actions.instantiate({ id, ...data })), - allocate: (template) => unwrapDispatch(actions.allocate({ template })), - clone: (id, data) => unwrapDispatch(actions.clone({ id, ...data })), - remove: (id, image) => unwrapDispatch(actions.remove({ id, image })), - update: (id, template, replace) => - unwrapDispatch(actions.update({ id, template, replace })), - changePermissions: (id, data) => - unwrapDispatch(actions.changePermissions({ id, ...data })), - changeOwnership: (id, ownership) => - unwrapDispatch(actions.changeOwnership({ id, ownership })), - rename: (id, newName) => - unwrapDispatch(actions.rename({ id, name: newName })), - lock: (id, data) => unwrapDispatch(actions.lock({ id, ...data })), - unlock: (id) => unwrapDispatch(actions.unlock({ id })), - } -} diff --git a/src/fireedge/src/client/features/One/vmTemplate/services.js b/src/fireedge/src/client/features/One/vmTemplate/services.js deleted file mode 100644 index 1b03c6977c..0000000000 --- a/src/fireedge/src/client/features/One/vmTemplate/services.js +++ /dev/null @@ -1,302 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/template' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const vmTemplateService = { - /** - * Retrieves information for the vm template. - * - * @param {object} params - Request parameters - * @param {string} params.id - Template id - * @param {boolean} params.extended - True to include extended information - * @param {boolean} params.decrypt - True to decrypt contained secrets (only admin) - * @returns {object} Get template identified by id - * @throws Fails when response isn't code 200 - */ - getVmTemplate: async (params) => { - const name = Actions.TEMPLATE_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.VMTEMPLATE ?? {} - }, - - /** - * Retrieves information for all or part of - * the virtual machine templates in the pool. - * - * @param {object} params - Request params - * @param {string} params.filter - Filter flag - * @param {number} params.start - Range start ID - * @param {number} params.end - Range end ID - * @returns {Array} List of VM templates - * @throws Fails when response isn't code 200 - */ - getVmTemplates: async (params) => { - const name = Actions.TEMPLATE_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.VMTEMPLATE_POOL?.VMTEMPLATE ?? []].flat() - }, - - /** - * Allocates a new template in OpenNebula. - * - * @param {object} params - Request params - * @param {string} params.template - A string containing the template contents - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - allocate: async (params) => { - const name = Actions.TEMPLATE_ALLOCATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Clones an existing virtual machine template. - * - * @param {object} params - Request params - * @param {number|string} params.id - The ID of the template to be cloned - * @param {string} params.name - Name for the new template - * @param {boolean} params.image - * - `true` to clone the template plus any image defined in DISK. - * The new IMAGE_ID is set into each DISK - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - clone: async (params) => { - const name = Actions.TEMPLATE_CLONE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Deletes the given template from the pool. - * - * @param {object} params - Request params - * @param {number|string} params.id - Template id - * @param {boolean} params.image - * - `true` to delete the template plus any image defined in DISK - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - delete: async (params) => { - const name = Actions.TEMPLATE_DELETE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Replaces the template contents. - * - * @param {object} params - Request params - * @param {number|string} params.id - Template id - * @param {string} params.template - The new template contents - * @param {0|1} params.replace - * - Update type: - * ``0``: Replace the whole template. - * ``1``: Merge new template with the existing one. - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - update: async (params) => { - const name = Actions.TEMPLATE_UPDATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, - - /** - * Changes the permission bits of a template. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Template id - * @param {{ - * ownerUse: number, - * ownerManage: number, - * ownerAdmin: number, - * groupUse: number, - * groupManage: number, - * groupAdmin: number, - * otherUse: number, - * otherManage: number, - * otherAdmin: number - * }} params.permissions - Permissions data - * @param {boolean} params.image - * - `true` to chmod the template plus any image defined in DISK - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - changePermissions: async ({ id, image, permissions }) => { - const name = Actions.TEMPLATE_CHMOD - const command = { name, ...Commands[name] } - const config = requestConfig({ id, image, ...permissions }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Changes the ownership of a template. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Template id - * @param {{user: number, group: number}} params.ownership - Ownership data - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - changeOwnership: async ({ id, ownership }) => { - const name = Actions.TEMPLATE_CHOWN - const command = { name, ...Commands[name] } - const config = requestConfig({ id, ...ownership }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Renames a Template. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Template id - * @param {string} params.name - New name - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - rename: async (params) => { - const name = Actions.TEMPLATE_RENAME - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Locks a Template. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Template id - * @param {1|2|3|4} params.level - * - Lock level: - * ``1``: Use - * ``2``: Manage - * ``3``: Admin - * ``4``: All - * @param {boolean} params.test - Check if the object is already locked to return an error - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - lock: async (params) => { - const name = Actions.TEMPLATE_LOCK - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Unlocks a Template. - * - * @param {object} params - Request parameters - * @param {string|number} params.id - Template id - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - unlock: async (params) => { - const name = Actions.TEMPLATE_UNLOCK - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data - - return res?.data - }, - - /** - * Instantiates a new virtual machine from a template. - * - * @param {object} params - Request params - * @param {number|string} params.id - Template id - * @param {string} params.name - Name for the new VM instance - * @param {boolean} params.hold - True to create it on hold state - * @param {boolean} params.persistent - True to create a private persistent copy - * @param {string} params.template - Extra template to be merged with the one being instantiated - * @returns {number} Template id - * @throws Fails when response isn't code 200 - */ - instantiate: async (params) => { - const name = Actions.TEMPLATE_INSTANTIATE - const command = { name, ...Commands[name] } - const config = requestConfig(params, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data - }, -} diff --git a/src/fireedge/src/client/features/One/vnetwork/actions.js b/src/fireedge/src/client/features/One/vnetwork/actions.js deleted file mode 100644 index 3370aaebda..0000000000 --- a/src/fireedge/src/client/features/One/vnetwork/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { vNetworkService } from 'client/features/One/vnetwork/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.vn} */ -const VNET = 'vn' - -export const getVNetwork = createAction( - `${VNET}/detail`, - vNetworkService.getVNetwork -) - -export const getVNetworks = createAction( - `${VNET}/pool`, - vNetworkService.getVNetworks, - (response) => ({ [RESOURCES.vn]: response }) -) diff --git a/src/fireedge/src/client/features/One/vnetwork/hooks.js b/src/fireedge/src/client/features/One/vnetwork/hooks.js deleted file mode 100644 index e924f95e4c..0000000000 --- a/src/fireedge/src/client/features/One/vnetwork/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/vnetwork/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useVNetwork = () => - useSelector((state) => state[name]?.[RESOURCES.vn] ?? []) - -export const useVNetworkApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getVNetwork: (id) => unwrapDispatch(actions.getVNetwork({ id })), - getVNetworks: () => unwrapDispatch(actions.getVNetworks()), - } -} diff --git a/src/fireedge/src/client/features/One/vnetwork/services.js b/src/fireedge/src/client/features/One/vnetwork/services.js deleted file mode 100644 index eaee6e404b..0000000000 --- a/src/fireedge/src/client/features/One/vnetwork/services.js +++ /dev/null @@ -1,63 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vn' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const vNetworkService = { - /** - * Retrieves information for the virtual network. - * - * @param {object} data - Request parameters - * @param {string} data.id - Virtual network id - * @returns {object} Get virtual network identified by id - * @throws Fails when response isn't code 200 - */ - getVNetwork: async ({ id }) => { - const name = Actions.VN_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.VNET ?? {} - }, - - /** - * Retrieves information for all or part of the - * virtual networks in the pool. - * - * @param {object} data - Request params - * @param {string} data.filter - Filter flag - * @param {number} data.start - Range start ID - * @param {number} data.end - Range end ID - * @returns {Array} List of virtual networks - * @throws Fails when response isn't code 200 - */ - getVNetworks: async ({ filter, start, end }) => { - const name = Actions.VN_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ filter, start, end }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.VNET_POOL?.VNET ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/vnetworkTemplate/actions.js b/src/fireedge/src/client/features/One/vnetworkTemplate/actions.js deleted file mode 100644 index d577d987eb..0000000000 --- a/src/fireedge/src/client/features/One/vnetworkTemplate/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { vNetworkTemplateService } from 'client/features/One/vnetworkTemplate/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.vntemplate} */ -const VNET_TEMPLATE = 'vntemplate' - -export const getVNetworkTemplate = createAction( - `${VNET_TEMPLATE}/detail`, - vNetworkTemplateService.getVNetworkTemplate -) - -export const getVNetworkTemplates = createAction( - `${VNET_TEMPLATE}/pool`, - vNetworkTemplateService.getVNetworkTemplates, - (response) => ({ [RESOURCES.vntemplate]: response }) -) diff --git a/src/fireedge/src/client/features/One/vnetworkTemplate/hooks.js b/src/fireedge/src/client/features/One/vnetworkTemplate/hooks.js deleted file mode 100644 index 6e395f331c..0000000000 --- a/src/fireedge/src/client/features/One/vnetworkTemplate/hooks.js +++ /dev/null @@ -1,40 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/vnetworkTemplate/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useVNetworkTemplate = () => - useSelector((state) => state[name]?.[RESOURCES.vntemplate] ?? []) - -export const useVNetworkTemplateApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getVNetworkTemplate: (id) => - unwrapDispatch(actions.getVNetworkTemplate({ id })), - getVNetworkTemplates: () => unwrapDispatch(actions.getVNetworkTemplates()), - } -} diff --git a/src/fireedge/src/client/features/One/vnetworkTemplate/services.js b/src/fireedge/src/client/features/One/vnetworkTemplate/services.js deleted file mode 100644 index 66c48c8fb8..0000000000 --- a/src/fireedge/src/client/features/One/vnetworkTemplate/services.js +++ /dev/null @@ -1,63 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vntemplate' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const vNetworkTemplateService = { - /** - * Retrieves information for the virtual network template. - * - * @param {object} data - Request parameters - * @param {string} data.id - Virtual Network Template id - * @returns {object} Get virtual network template identified by id - * @throws Fails when response isn't code 200 - */ - getVNetworkTemplate: async ({ id }) => { - const name = Actions.VNTEMPLATE_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.VNTEMPLATE ?? {} - }, - - /** - * Retrieves information for all or part of th - * virtual network templates in the pool. - * - * @param {object} data - Request params - * @param {string} data.filter - Filter flag - * @param {number} data.start - Range start ID - * @param {number} data.end - Range end ID - * @returns {Array} List of virtual network templates - * @throws Fails when response isn't code 200 - */ - getVNetworkTemplates: async ({ filter, start, end }) => { - const name = Actions.VNTEMPLATE_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ filter, start, end }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.VNTEMPLATE_POOL?.VNTEMPLATE ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/vrouter/actions.js b/src/fireedge/src/client/features/One/vrouter/actions.js deleted file mode 100644 index 1f33ea11bf..0000000000 --- a/src/fireedge/src/client/features/One/vrouter/actions.js +++ /dev/null @@ -1,32 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { vRouterService } from 'client/features/One/vrouter/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.vrouter} */ -const VROUTER = 'vrouter' - -export const getVRouter = createAction( - `${VROUTER}/detail`, - vRouterService.getVRouter -) - -export const getVRouters = createAction( - `${VROUTER}/pool`, - vRouterService.getVRouters, - (response) => ({ [RESOURCES.vrouter]: response }) -) diff --git a/src/fireedge/src/client/features/One/vrouter/hooks.js b/src/fireedge/src/client/features/One/vrouter/hooks.js deleted file mode 100644 index b15fced304..0000000000 --- a/src/fireedge/src/client/features/One/vrouter/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/vrouter/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useVRouter = () => - useSelector((state) => state[name]?.[RESOURCES.vrouter] ?? []) - -export const useVRouterApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getVRouter: (id) => unwrapDispatch(actions.getVRouter({ id })), - getVRouters: () => unwrapDispatch(actions.getVRouters()), - } -} diff --git a/src/fireedge/src/client/features/One/vrouter/services.js b/src/fireedge/src/client/features/One/vrouter/services.js deleted file mode 100644 index f5addf3e72..0000000000 --- a/src/fireedge/src/client/features/One/vrouter/services.js +++ /dev/null @@ -1,63 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vrouter' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const vRouterService = { - /** - * Retrieves information for the virtual router. - * - * @param {object} data - Request parameters - * @param {string} data.id - Virtual router id - * @returns {object} Get virtual router identified by id - * @throws Fails when response isn't code 200 - */ - getVRouter: async ({ id }) => { - const name = Actions.VROUTER_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.VROUTER ?? {} - }, - - /** - * Retrieves information for all or part of the - * virtual routers in the pool. - * - * @param {object} data - Request params - * @param {string} data.filter - Filter flag - * @param {number} data.start - Range start ID - * @param {number} data.end - Range end ID - * @returns {Array} List of virtual routers - * @throws Fails when response isn't code 200 - */ - getVRouters: async ({ filter, start, end }) => { - const name = Actions.VROUTER_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ filter, start, end }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.VROUTER_POOL?.VROUTER ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/One/zone/actions.js b/src/fireedge/src/client/features/One/zone/actions.js deleted file mode 100644 index 8cab4e76be..0000000000 --- a/src/fireedge/src/client/features/One/zone/actions.js +++ /dev/null @@ -1,29 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { createAction } from 'client/features/One/utils' -import { zoneService } from 'client/features/One/zone/services' -import { RESOURCES } from 'client/features/One/slice' - -/** @see {@link RESOURCES.zone} */ -const ZONE = 'zone' - -export const getZone = createAction(`${ZONE}/detail`, zoneService.getZone) - -export const getZones = createAction( - `${ZONE}/pool`, - zoneService.getZones, - (response) => ({ [RESOURCES.zone]: response }) -) diff --git a/src/fireedge/src/client/features/One/zone/hooks.js b/src/fireedge/src/client/features/One/zone/hooks.js deleted file mode 100644 index 74a03ad82d..0000000000 --- a/src/fireedge/src/client/features/One/zone/hooks.js +++ /dev/null @@ -1,39 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { useCallback } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { unwrapResult } from '@reduxjs/toolkit' - -import * as actions from 'client/features/One/zone/actions' -import { name, RESOURCES } from 'client/features/One/slice' - -export const useZone = () => - useSelector((state) => state[name]?.[RESOURCES.zone] ?? []) - -export const useZoneApi = () => { - const dispatch = useDispatch() - - const unwrapDispatch = useCallback( - (action) => dispatch(action).then(unwrapResult), - [dispatch] - ) - - return { - getZone: (id) => unwrapDispatch(actions.getZone({ id })), - getZones: () => unwrapDispatch(actions.getZones()), - } -} diff --git a/src/fireedge/src/client/features/One/zone/services.js b/src/fireedge/src/client/features/One/zone/services.js deleted file mode 100644 index 165a9245cf..0000000000 --- a/src/fireedge/src/client/features/One/zone/services.js +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/zone' -import { httpCodes } from 'server/utils/constants' -import { requestConfig, RestClient } from 'client/utils' - -export const zoneService = { - /** - * Retrieves information for the zone. - * - * @param {object} data - Request parameters - * @param {string} data.id - Zone id - * @returns {object} Get zone identified by id - * @throws Fails when response isn't code 200 - */ - getZone: async ({ id }) => { - const name = Actions.ZONE_INFO - const command = { name, ...Commands[name] } - const config = requestConfig({ id }, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return res?.data?.ZONE ?? {} - }, - - /** - * Retrieves information for all the zones in the pool. - * - * @returns {Array} List of zones - * @throws Fails when response isn't code 200 - */ - getZones: async () => { - const name = Actions.ZONE_POOL_INFO - const command = { name, ...Commands[name] } - const config = requestConfig(undefined, command) - - const res = await RestClient.request(config) - - if (!res?.id || res?.id !== httpCodes.ok.id) throw res - - return [res?.data?.ZONE_POOL?.ZONE ?? []].flat() - }, -} diff --git a/src/fireedge/src/client/features/OneApi/cluster.js b/src/fireedge/src/client/features/OneApi/cluster.js new file mode 100644 index 0000000000..827c877461 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/cluster.js @@ -0,0 +1,279 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/cluster' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { Cluster } from 'client/constants' + +const { CLUSTER } = ONE_RESOURCES + +const clusterApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getClusters: builder.query({ + /** + * Retrieves information for all the clusters in the pool. + * + * @returns {Cluster[]} List of clusters + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.CLUSTER_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.CLUSTER_POOL?.CLUSTER ?? []].flat(), + providesTags: [CLUSTER], + }), + getCluster: builder.query({ + /** + * Retrieves information for the cluster. + * + * @param {object} params - Request params + * @param {string} params.id - Cluster id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {Cluster} Get cluster identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.CLUSTER ?? {}, + providesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + async onQueryStarted({ id }, { dispatch, queryFulfilled }) { + try { + const { data: queryVm } = await queryFulfilled + + dispatch( + clusterApi.util.updateQueryData( + 'getClusters', + undefined, + (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryVm) + } + ) + ) + } catch {} + }, + }), + allocateCluster: builder.mutation({ + /** + * Allocates a new cluster in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.name - Name for the new cluster + * @returns {number} The allocated cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [CLUSTER], + }), + removeCluster: builder.mutation({ + /** + * Deletes the given cluster from the pool. + * + * @param {number|string} id - Cluster id + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.CLUSTER_DELETE + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: [CLUSTER], + }), + updateCluster: builder.mutation({ + /** + * Replaces the cluster template contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - Cluster id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + }), + addHostToCluster: builder.mutation({ + /** + * Adds a host to the given cluster. + * + * @param {object} params - Request params + * @param {number|string} params.id - The cluster id + * @param {string} params.host - The host id + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_ADDHOST + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + }), + removeHostFromCluster: builder.mutation({ + /** + * Removes a host from the given cluster. + * + * @param {object} params - Request params + * @param {number|string} params.id - The cluster id + * @param {string} params.host - The host id + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_DELHOST + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + }), + addDatastoreToCluster: builder.mutation({ + /** + * Adds a datastore to the given cluster. + * + * @param {object} params - Request params + * @param {number|string} params.id - The cluster id + * @param {string} params.datastore - The datastore id + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_ADDDATASTORE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + }), + removeDatastoreFromCluster: builder.mutation({ + /** + * Removes a datastore from the given cluster. + * + * @param {object} params - Request params + * @param {number|string} params.id - The cluster id + * @param {string} params.datastore - The datastore id + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_DELDATASTORE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + }), + addNetworkToCluster: builder.mutation({ + /** + * Adds a vnet to the given cluster. + * + * @param {object} params - Request params + * @param {number|string} params.id - The cluster id + * @param {string} params.vnet - The vnet id + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_ADDVNET + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + }), + removeNetworkFromCluster: builder.mutation({ + /** + * Removes a vnet from the given cluster. + * + * @param {object} params - Request params + * @param {number|string} params.id - The cluster id + * @param {string} params.vnet - The vnet id + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_DELVNET + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }], + }), + renameCluster: builder.mutation({ + /** + * Renames a cluster. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Cluster id + * @param {string} params.name - The new name + * @returns {number} Cluster id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.CLUSTER_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: CLUSTER, id }, CLUSTER], + }), + }), +}) + +export const { + // Queries + useGetClustersQuery, + useLazyGetClustersQuery, + useGetClusterQuery, + useLazyGetClusterQuery, + + // Mutations + useAllocateClusterMutation, + useRemoveClusterMutation, + useUpdateClusterMutation, + useAddHostToClusterMutation, + useRemoveHostFromClusterMutation, + useAddDatastoreToClusterMutation, + useRemoveDatastoreFromClusterMutation, + useAddNetworkToClusterMutation, + useRemoveNetworkFromClusterMutation, + useRenameClusterMutation, +} = clusterApi + +export default clusterApi diff --git a/src/fireedge/src/client/features/OneApi/datastore.js b/src/fireedge/src/client/features/OneApi/datastore.js new file mode 100644 index 0000000000..9476b65905 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/datastore.js @@ -0,0 +1,234 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/datastore' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { Permission, Datastore } from 'client/constants' + +const { DATASTORE } = ONE_RESOURCES + +const datastoreApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getDatastores: builder.query({ + /** + * Retrieves information for all or part of the datastores in the pool. + * + * @returns {Datastore[]} List of datastores + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.DATASTORE_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => + [data?.DATASTORE_POOL?.DATASTORE ?? []].flat(), + providesTags: [DATASTORE], + }), + getDatastore: builder.query({ + /** + * Retrieves information for the datastore. + * + * @param {object} params - Request params + * @param {string|number} params.id - Datastore id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {Datastore} Get datastore identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.DATASTORE_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.DATASTORE ?? {}, + invalidatesTags: (_, __, { id }) => [{ type: DATASTORE, id }], + }), + allocateDatastore: builder.mutation({ + /** + * Allocates a new datastore in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - The string containing the template of the resource on syntax XML + * @param {number|'-1'} params.cluster - The cluster ID. If it's -1, the default one will be used + * @returns {number} The allocated datastore id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.DATASTORE_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [DATASTORE], + }), + removeDatastore: builder.mutation({ + /** + * Deletes the given datastore from the pool. + * + * @param {number|string} id - Datastore id + * @returns {number} Datastore id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.DATASTORE_DELETE + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: [DATASTORE], + }), + updateDatastore: builder.mutation({ + /** + * Replaces the datastore contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - Datastore id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Datastore id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.DATASTORE_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: DATASTORE, id }], + }), + changeDatastorePermissions: builder.mutation({ + /** + * Changes the permission bits of a virtual network. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual network id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: DATASTORE, id }], + }), + changeDatastoreOwnership: builder.mutation({ + /** + * Changes the ownership of a datastore. + * If set to `-1`, the user or group aren't changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Datastore id + * @param {number|'-1'} params.user - The user id + * @param {number|'-1'} params.group - The group id + * @returns {number} Datastore id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.DATASTORE_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: DATASTORE, id }, DATASTORE], + }), + renameDatastore: builder.mutation({ + /** + * Renames a datastore. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Datastore id + * @param {string} params.name - The new name + * @returns {number} Datastore id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.DATASTORE_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: DATASTORE, id }, DATASTORE], + }), + enableDatastore: builder.mutation({ + /** + * Sets the status of the datastore to enabled. + * + * @param {number|string} id - Datastore id + * @returns {number} Datastore id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.DATASTORE_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: true }, command } + }, + invalidatesTags: (_, __, id) => [{ type: DATASTORE, id }, DATASTORE], + }), + disableDatastore: builder.mutation({ + /** + * Sets the status of the datastore to disabled. + * + * @param {number|string} id - Datastore id + * @returns {number} Datastore id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.DATASTORE_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: false }, command } + }, + invalidatesTags: (_, __, id) => [{ type: DATASTORE, id }, DATASTORE], + }), + }), +}) + +export const { + // Queries + useGetDatastoreQuery, + useLazyGetDatastoreQuery, + useGetDatastoresQuery, + useLazyGetDatastoresQuery, + + // Mutations + useAllocateDatastoreMutation, + useRemoveDatastoreMutation, + useUpdateDatastoreMutation, + useChangeDatastorePermissionsMutation, + useChangeDatastoreOwnershipMutation, + useRenameDatastoreMutation, + useEnableDatastoreMutation, + useDisableDatastoreMutation, +} = datastoreApi + +export default datastoreApi diff --git a/src/fireedge/src/client/features/OneApi/group.js b/src/fireedge/src/client/features/OneApi/group.js new file mode 100644 index 0000000000..c2089a5a92 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/group.js @@ -0,0 +1,219 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/group' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { Group } from 'client/constants' + +const { GROUP } = ONE_RESOURCES + +const groupApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getGroups: builder.query({ + /** + * Retrieves information for all the groups in the pool. + * + * @returns {Group[]} Get list of groups + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.GROUP_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.GROUP_POOL?.GROUP ?? []].flat(), + providesTags: [GROUP], + }), + getGroup: builder.query({ + /** + * Retrieves information for the group. + * + * @param {string|number} id - Group id + * @returns {Group} Get group identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.GROUP_INFO + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.GROUP ?? {}, + invalidatesTags: (_, __, id) => [{ type: GROUP, id }], + }), + allocateGroup: builder.mutation({ + /** + * Allocates a new group in OpenNebula. + * + * @param {object} params - Request parameters + * @param {string} params.name - Name for the new group + * @returns {number} The allocated Group id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.GROUP_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [GROUP], + }), + updateGroup: builder.mutation({ + /** + * Replaces the group template contents. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Group id + * @param {string} params.template - The new template contents on syntax XML + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Group id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.GROUP_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: GROUP, id }], + }), + removeGroup: builder.mutation({ + /** + * Deletes the given group from the pool. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Group id + * @returns {number} Group id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.GROUP_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [GROUP], + }), + addAdminToGroup: builder.mutation({ + /** + * Adds a User to the Group administrators set. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Group id + * @param {string|number} params.user - User id + * @returns {number} Group id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.GROUP_ADDADMIN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: GROUP, id }], + }), + removeAdminFromGroup: builder.mutation({ + /** + * Removes a User from the Group administrators set. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Group id + * @param {string|number} params.user - User id + * @returns {number} Group id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.GROUP_DELADMIN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: GROUP, id }], + }), + getGroupQuota: builder.query({ + /** + * Returns the default group quota limits. + * + * @returns {string} The quota template contents + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.GROUP_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + }), + updateGroupQuota: builder.mutation({ + /** + * Sets the group quota limits. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Group id + * @param {string|number} params.template - The new quota template contents on syntax XML + * @returns {string} The quota template contents + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.GROUP_QUOTA + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: GROUP, id }], + }), + updateDefaultGroupQuota: builder.mutation({ + /** + * Updates the default group quota limits. + * + * @param {object} params - Request parameters + * @param {string|number} params.template - The new quota template contents on syntax XML + * @returns {string} The quota template contents + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.GROUP_QUOTA_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + }), +}) + +export const { + // Queries + useGetGroupQuery, + useLazyGetGroupQuery, + useGetGroupsQuery, + useLazyGetGroupsQuery, + useGetGroupQuotaQuery, + useLazyGetGroupQuotaQuery, + + // Mutations + useAllocateGroupMutation, + useUpdateGroupMutation, + useRemoveGroupMutation, + useAddAdminToGroupMutation, + useRemoveAdminFromGroupMutation, + useUpdateGroupQuotaMutation, + useUpdateDefaultGroupQuotaMutation, +} = groupApi + +export default groupApi diff --git a/src/fireedge/src/client/features/OneApi/host.js b/src/fireedge/src/client/features/OneApi/host.js new file mode 100644 index 0000000000..e7be460324 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/host.js @@ -0,0 +1,275 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/host' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { UpdateFromSocket } from 'client/features/OneApi/socket' +import { Host } from 'client/constants' + +const { HOST } = ONE_RESOURCES + +const hostApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getHosts: builder.query({ + /** + * Retrieves information for all the hosts in the pool. + * + * @returns {Host[]} Get list of hosts + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.HOST_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.HOST_POOL?.HOST ?? []].flat(), + providesTags: [HOST], + }), + getHost: builder.query({ + /** + * Retrieves information for the host. + * + * @param {string} id - Host id + * @returns {Host} Get host identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.HOST_INFO + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.HOST ?? {}, + providesTags: (_, __, id) => [{ type: HOST, id }], + async onQueryStarted(id, { dispatch, queryFulfilled }) { + try { + const { data: queryVm } = await queryFulfilled + + dispatch( + hostApi.util.updateQueryData('getHosts', undefined, (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryVm) + }) + ) + } catch {} + }, + onCacheEntryAdded: UpdateFromSocket({ + updateQueryData: (updateFn) => + hostApi.util.updateQueryData('getHosts', undefined, updateFn), + resource: HOST.toLowerCase(), + }), + }), + allocateHost: builder.mutation({ + /** + * Allocates a new host in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.hostname - Hostname of the machine we want to add + * @param {string} params.imMad + * - The name of the information manager (im_mad_name), + * this values are taken from the oned.conf with the tag name IM_MAD (name) + * @param {string} params.vmmMad + * - The name of the virtual machine manager mad name (vmm_mad_name), + * this values are taken from the oned.conf with the tag name VM_MAD (name) + * @param {string|number} [params.cluster] - The cluster ID + * @returns {number} Host id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.HOST_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [HOST], + }), + updateHost: builder.mutation({ + /** + * Replaces the host’s template contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - Host id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Host id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.HOST_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: HOST, id }], + }), + removeHost: builder.mutation({ + /** + * Deletes the given host from the pool. + * + * @param {object} params - Request params + * @param {number|string} params.id - Host id + * @returns {number} Host id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.HOST_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [HOST], + }), + enableHost: builder.mutation({ + /** + * Sets the status of the host to enabled. + * + * @param {number|string} id - Host id + * @returns {number} Host id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.HOST_STATUS + const command = { name, ...Commands[name] } + + return { params: { id, status: 0 }, command } + }, + invalidatesTags: (_, __, id) => [{ type: HOST, id }, HOST], + }), + disableHost: builder.mutation({ + /** + * Sets the status of the host to disabled. + * + * @param {number|string} id - Host id + * @returns {number} Host id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.HOST_STATUS + const command = { name, ...Commands[name] } + + return { params: { id, status: 1 }, command } + }, + invalidatesTags: (_, __, id) => [{ type: HOST, id }, HOST], + }), + offlineHost: builder.mutation({ + /** + * Sets the status of the host to offline. + * + * @param {number|string} id - Host id + * @returns {number} Host id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.HOST_STATUS + const command = { name, ...Commands[name] } + + return { params: { id, status: 2 }, command } + }, + invalidatesTags: (_, __, id) => [{ type: HOST, id }, HOST], + }), + renameHost: builder.mutation({ + /** + * Renames a host. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Host id + * @param {string} params.name - New name + * @returns {number} Host id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.HOST_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: HOST, id }], + async onQueryStarted({ id, name }, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + hostApi.util.updateQueryData('getHosts', undefined, (draft) => { + const host = draft.find(({ ID }) => +ID === +id) + host && (host.NAME = name) + }) + ) + } catch {} + }, + }), + getHostMonitoring: builder.query({ + /** + * Returns the host monitoring records. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Host id + * @returns {string} The monitoring information string / The error string + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.HOST_MONITORING + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + getHostMonitoringPool: builder.query({ + /** + * Returns all the host monitoring records. + * + * @param {object} params - Request parameters + * @param {number|'0'|'-1'} [params.seconds] + * - Retrieve monitor records in the last num seconds. + * `0`: Only the last record. + * `-1`: All records. + * @returns {string} The monitoring information string / The error string + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.HOST_POOL_MONITORING + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + }), +}) + +export const { + // Queries + useGetHostQuery, + useLazyGetHostQuery, + useGetHostsQuery, + useLazyGetHostsQuery, + useGetHostMonitoringQuery, + useLazyGetHostMonitoringQuery, + useGetHostMonitoringPoolQuery, + useLazyGetHostMonitoringPoolQuery, + + // Mutations + useAllocateHostMutation, + useUpdateHostMutation, + useRemoveHostMutation, + useEnableHostMutation, + useDisableHostMutation, + useOfflineHostMutation, + useRenameHostMutation, +} = hostApi + +export default hostApi diff --git a/src/fireedge/src/client/features/OneApi/image.js b/src/fireedge/src/client/features/OneApi/image.js new file mode 100644 index 0000000000..af4d4354ba --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/image.js @@ -0,0 +1,401 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/image' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { UpdateFromSocket } from 'client/features/OneApi/socket' +import { + FilterFlag, + Image, + Permission, + IMAGE_TYPES_STR, +} from 'client/constants' + +const { IMAGE } = ONE_RESOURCES + +const imageApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getImages: builder.query({ + /** + * Retrieves information for all or part of the images in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {Image[]} List of images + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => [data?.IMAGE_POOL?.IMAGE ?? []].flat(), + providesTags: [IMAGE], + }), + getImage: builder.query({ + /** + * Retrieves information for the image. + * + * @param {object} params - Request params + * @param {string|number} params.id - Image id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {Image} Get Image identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.IMAGE ?? {}, + providesTags: (_, __, { id }) => [{ type: IMAGE, id }], + onCacheEntryAdded: ({ id }, endpointProps) => + UpdateFromSocket({ + updateQueryData: (updateFn) => + imageApi.util.updateQueryData('getImages', undefined, updateFn), + resource: IMAGE.toLowerCase(), + })(id, endpointProps), + }), + allocateImage: builder.mutation({ + /** + * Allocates a new image in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - A string containing the template of the image on syntax XML + * @param {string} params.id - The datastore ID + * @param {boolean} [params.capacity] - `true` to avoid checking datastore capacity + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [IMAGE], + }), + cloneImage: builder.mutation({ + /** + * Clones an existing image. + * + * @param {object} params - Request params + * @param {string} params.id - The id of the image to be cloned + * @param {string} params.name - Name for the new image + * @param {string|-1} [params.datastore] - The ID of the target datastore + * @returns {number} The new image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_CLONE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [IMAGE], + }), + removeImage: builder.mutation({ + /** + * Deletes the given image from the pool. + * + * @param {object} params - Request params + * @param {string} params.id - The object id + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [IMAGE], + }), + enableImage: builder.mutation({ + /** + * Enables an image. + * + * @param {string} id - Image id + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.IMAGE_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: true }, command } + }, + invalidatesTags: (_, __, id) => [{ type: IMAGE, id }, IMAGE], + }), + disableImage: builder.mutation({ + /** + * Disables an image. + * + * @param {string} id - Image id + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.IMAGE_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: false }, command } + }, + invalidatesTags: (_, __, id) => [{ type: IMAGE, id }, IMAGE], + }), + persistentImage: builder.mutation({ + /** + * Sets the Image as persistent or not persistent. + * + * @param {number|string} params - Request params + * @param {string} params.id - Image id + * @param {boolean} params.persistent - `True` for persistent + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_PERSISTENT + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, id) => [{ type: IMAGE, id }, IMAGE], + }), + changeImageType: builder.mutation({ + /** + * Changes the type of an Image. + * + * @param {number|string} params - Request params + * @param {string} params.id - Image id + * @param {IMAGE_TYPES_STR} params.type - New type for the Image + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_CHTYPE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, id) => [{ type: IMAGE, id }, IMAGE], + }), + updateImage: builder.mutation({ + /** + * Replaces the image template contents. + * + * @param {number|string} params - Request params + * @param {string} params.id - Image id + * @param {string} params.template - The new template contents on syntax XML + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, id) => [{ type: IMAGE, id }], + }), + changeImagePermissions: builder.mutation({ + /** + * Changes the permission bits of a Image. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Image id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: IMAGE, id }], + }), + changeImageOwnership: builder.mutation({ + /** + * Changes the ownership of a Image. + * If set `user` or `group` to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Image id + * @param {string|number|'-1'} [params.userId] - User id + * @param {Permission|'-1'} [params.groupId] - Group id + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: IMAGE, id }, IMAGE], + }), + renameImage: builder.mutation({ + /** + * Renames a Image. + * + * @param {object} params - Request parameters + * @param {string} params.id - Image id + * @param {string} params.name - The new name + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: IMAGE, id }, IMAGE], + }), + deleteImageSnapshot: builder.mutation({ + /** + * Deletes a snapshot from the Image. + * + * @param {object} params - Request parameters + * @param {string} params.id - Image id + * @param {string} params.snapshot - ID of the snapshot to delete + * @returns {number} Snapshot ID + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_SNAPDEL + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: IMAGE, id }], + }), + revertImageSnapshot: builder.mutation({ + /** + * Reverts image state to a previous snapshot. + * + * @param {object} params - Request parameters + * @param {string} params.id - Image id + * @param {string} params.snapshot - ID of the snapshot to revert to + * @returns {number} Snapshot ID + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_SNAPREV + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: IMAGE, id }], + }), + flattenImageSnapshot: builder.mutation({ + /** + * Flatten the snapshot of image and discards others. + * + * @param {object} params - Request parameters + * @param {string} params.id - Image id + * @param {string} params.snapshot - ID of the snapshot to revert to + * @returns {number} Snapshot ID + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_SNAPFLAT + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: IMAGE, id }], + }), + lockImage: builder.mutation({ + /** + * Locks an image. Lock certain actions depending on blocking level. + * - `USE` (1): locks Admin, Manage and Use actions. + * - `MANAGE` (2): locks Manage and Use actions. + * - `ADMIN` (3): locks only Admin actions. + * - `ALL` (4): locks all actions. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Image id + * @param {'1'|'2'|'3'|'4'} params.lock - Lock level + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_LOCK + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: IMAGE, id }, IMAGE], + }), + unlockImage: builder.mutation({ + /** + * Unlocks an image. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Image id + * @returns {number} Image id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.IMAGE_UNLOCK + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, id) => [{ type: IMAGE, id }, IMAGE], + }), + }), +}) + +export const { + // Queries + useGetImageQuery, + useLazyGetImageQuery, + useGetImagesQuery, + useLazyGetImagesQuery, + + // Mutations + useAllocateImageMutation, + useCloneImageMutation, + useRemoveImageMutation, + useEnableImageMutation, + useDisableImageMutation, + usePersistentImageMutation, + useChangeImageTypeMutation, + useUpdateImageMutation, + useChangeImagePermissionsMutation, + useChangeImageOwnershipMutation, + useRenameImageMutation, + useDeleteImageSnapshotMutation, + useRevertImageSnapshotMutation, + useFlattenImageSnapshotMutation, + useLockImageMutation, + useUnlockImageMutation, +} = imageApi diff --git a/src/fireedge/src/client/features/OneApi/index.js b/src/fireedge/src/client/features/OneApi/index.js new file mode 100644 index 0000000000..1b942400b9 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/index.js @@ -0,0 +1,111 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { createApi } from '@reduxjs/toolkit/query/react' + +import { enqueueSnackbar } from 'client/features/General/actions' +import { logout } from 'client/features/Auth/actions' +import { httpCodes } from 'server/utils/constants' +import { requestConfig, generateKey } from 'client/utils' +import { T } from 'client/constants' +import http from 'client/utils/rest' + +const ONE_RESOURCES = { + ACL: 'Acl', + APP: 'App', + CLUSTER: 'Cluster', + DATASTORE: 'Datastore', + FILE: 'File', + GROUP: 'Group', + HOST: 'Host', + IMAGE: 'Image', + MARKETPLACE: 'Marketplace', + SECURITYGROUP: 'SecurityGroup', + SYSTEM: 'System', + TEMPLATE: 'Template', + USER: 'User', + VDC: 'Vdc', + VM: 'Vm', + VMGROUP: 'VmGroup', + VNET: 'VNetwork', + VNTEMPLATE: 'NetworkTemplate', + VROUTER: 'VirtualRouter', + ZONE: 'Zone', +} + +const DOCUMENT = { + SERVICE: 'applicationService', + SERVICE_TEMPLATE: 'applicationServiceTemplate', + PROVISION: 'provision', + PROVISION_TEMPLATE: 'provisionTemplate', + PROVIDER: 'provider', + PROVIDER_CONFIG: 'providerConfig', + PROVISION_RESOURCES: { + CLUSTER: 'provisionCluster', + DATASTORE: 'provisionDatastore', + HOST: 'provisionHost', + TEMPLATE: 'provisionVmTemplate', + IMAGE: 'provisionImage', + NETWORK: 'provisionVNetwork', + VNTEMPLATE: 'provisionNetworkTemplate', + FLOWTEMPLATE: 'provisionFlowTemplate', + }, +} + +const oneApi = createApi({ + reducerPath: 'oneApi', + baseQuery: async ({ params, command }, { dispatch, signal }) => { + try { + const config = requestConfig(params, command) + const response = await http.request({ ...config, signal }) + + return { data: response.data ?? {} } + } catch (axiosError) { + const { message, data, status, statusText } = axiosError + const error = message ?? data?.message ?? statusText + + status === httpCodes.unauthorized.id + ? dispatch(logout(T.SessionExpired)) + : dispatch( + enqueueSnackbar({ + key: generateKey(), + message: error, + options: { variant: 'error' }, + }) + ) + + return { + error: { + status: status, + data: message ?? data?.data ?? statusText, + }, + } + } + }, + refetchOnMountOrArgChange: 30, + tagTypes: [ + ...Object.values(ONE_RESOURCES), + DOCUMENT.SERVICE, + DOCUMENT.SERVICE_TEMPLATE, + DOCUMENT.PROVISION, + DOCUMENT.PROVISION_TEMPLATE, + DOCUMENT.PROVIDER, + DOCUMENT.PROVIDER_CONFIG, + ...Object.values(DOCUMENT.PROVISION_RESOURCES), + ], + endpoints: () => ({}), +}) + +export { oneApi, ONE_RESOURCES, DOCUMENT } diff --git a/src/fireedge/src/client/features/OneApi/marketplace.js b/src/fireedge/src/client/features/OneApi/marketplace.js new file mode 100644 index 0000000000..94b9d192c2 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/marketplace.js @@ -0,0 +1,240 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/market' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { Permission, Marketplace } from 'client/constants' + +const { MARKETPLACE } = ONE_RESOURCES + +const marketplaceApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getMarketplaces: builder.query({ + /** + * Retrieves information for all or part of the marketplaces in the pool. + * + * @returns {Marketplace[]} List of marketplaces + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.MARKET_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => + [data?.MARKETPLACE_POOL?.MARKETPLACE ?? []].flat(), + providesTags: [MARKETPLACE], + }), + getMarketplace: builder.query({ + /** + * Retrieves information for the marketplace. + * + * @param {object} params - Request params + * @param {string} params.id - Marketplace id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {Marketplace} Get marketplace identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKET_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.MARKETPLACE ?? {}, + providesTags: (_, __, { id }) => [{ type: MARKETPLACE, id }], + }), + allocateMarketplace: builder.mutation({ + /** + * Allocates a new marketplace in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - A string containing the template of the marketplace on syntax XML + * @returns {number} Marketplace id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKET_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [MARKETPLACE], + }), + removeMarketplace: builder.mutation({ + /** + * Deletes the given marketplace from the pool. + * + * @param {object} params - Request params + * @param {string} params.id - Marketplace id + * @returns {number} Marketplace id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKET_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [MARKETPLACE], + }), + updateMarketplace: builder.mutation({ + /** + * Replaces the marketplace template contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - Marketplace id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKET_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + providesTags: (_, __, { id }) => [{ type: MARKETPLACE, id }], + }), + changeMarketplacePermissions: builder.mutation({ + /** + * Changes the permission bits of a marketplace. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @returns {number} Marketplace id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKET_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: MARKETPLACE, id }], + }), + changeMarketplaceOwnership: builder.mutation({ + /** + * Changes the ownership of a marketplace. + * If set `user` or `group` to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace id + * @param {string|'-1'} [params.userId] - User id + * @param {string|'-1'} [params.groupId] - Group id + * @returns {number} Marketplace id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKET_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [ + { type: MARKETPLACE, id }, + MARKETPLACE, + ], + }), + renameMarketplace: builder.mutation({ + /** + * Renames a marketplace. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace id + * @param {string} params.name - The new name + * @returns {number} Marketplace id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKET_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [ + { type: MARKETPLACE, id }, + MARKETPLACE, + ], + }), + enableMarketplace: builder.mutation({ + /** + * Enables a marketplace. + * + * @param {object} params - Request params + * @param {number} params.id - Marketplace id + * @returns {number} Marketplace id + * @throws Fails when response isn't code 200 + */ + query: ({ id }) => { + const name = Actions.MARKET_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: true }, command } + }, + invalidatesTags: (_, __, id) => [{ type: MARKETPLACE, id }, MARKETPLACE], + }), + disableMarketplace: builder.mutation({ + /** + * Disables a marketplace. + * + * @param {object} params - Request params + * @param {number} params.id - Marketplace id + * @returns {number} Marketplace id + * @throws Fails when response isn't code 200 + */ + query: ({ id }) => { + const name = Actions.MARKET_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: false }, command } + }, + invalidatesTags: (_, __, id) => [{ type: MARKETPLACE, id }, MARKETPLACE], + }), + }), +}) + +export const { + // Queries + useGetMarketplaceQuery, + useLazyGetMarketplaceQuery, + useGetMarketplacesQuery, + useLazyGetMarketplacesQuery, + + // Mutations + useAllocateMarketplaceMutation, + useRemoveMarketplaceMutation, + useUpdateMarketplaceMutation, + useChangeMarketplacePermissionsMutation, + useChangeMarketplaceOwnershipMutation, + useRenameMarketplaceMutation, + useEnableMarketplaceMutation, + useDisableMarketplaceMutation, +} = marketplaceApi diff --git a/src/fireedge/src/client/features/OneApi/marketplaceApp.js b/src/fireedge/src/client/features/OneApi/marketplaceApp.js new file mode 100644 index 0000000000..f191dd67ea --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/marketplaceApp.js @@ -0,0 +1,348 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/marketapp' +import { + Actions as ExtraActions, + Commands as ExtraCommands, +} from 'server/routes/api/marketapp/routes' + +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { FilterFlag, Permission, MarketplaceApp } from 'client/constants' + +const { APP } = ONE_RESOURCES + +const marketAppApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getMarketplaceApps: builder.query({ + /** + * Retrieves information for all or part of the + * marketplace apps in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {MarketplaceApp[]} List of marketplace apps + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKETAPP_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => + [data?.MARKETPLACEAPP_POOL?.MARKETPLACEAPP ?? []].flat(), + providesTags: [APP], + }), + getMarketplaceApp: builder.query({ + /** + * Retrieves information for the marketplace app. + * + * @param {string} id - Marketplace apps id + * @returns {MarketplaceApp} Get marketplace app identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.MARKETAPP_INFO + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.MARKETPLACEAPP ?? {}, + providesTags: (_, __, id) => [{ type: APP, id }], + }), + getDockerHubTags: builder.query({ + /** + * Retrieves DockerHub tags information for marketplace app. + * + * @param {object} params - Request parameters + * @param {string} params.id - App id + * @param {string} [params.page] - Number of page + * @returns {object[]} List of DockerHub tags + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = ExtraActions.MARKETAPP_DOCKERTAGS + const command = { name, ...ExtraCommands[name] } + + return { params, command } + }, + }), + allocateApp: builder.mutation({ + /** + * Allocates a new marketplace app in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - A string containing the template of the marketplace app on syntax XML + * @param {string} params.id - The Marketplace ID + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKETAPP_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [APP], + }), + updateApp: builder.mutation({ + /** + * Replaces the marketplace app template contents. + * + * @param {object} params - Request params + * @param {string} params.id - Marketplace app id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKETAPP_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + providesTags: (_, __, { id }) => [{ type: APP, id }], + }), + removeApp: builder.mutation({ + /** + * Deletes the given marketplace app from the pool. + * + * @param {string} id - Marketplace app id + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.MARKETAPP_DELETE + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + providesTags: [APP], + }), + enableApp: builder.mutation({ + /** + * Enables a marketplace app. + * + * @param {string} id - Marketplace app id + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.MARKETAPP_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: true }, command } + }, + invalidatesTags: (_, __, id) => [{ type: APP, id }, APP], + }), + disableApp: builder.mutation({ + /** + * Disables a marketplace app. + * + * @param {string} id - Marketplace app id + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.MARKETAPP_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: false }, command } + }, + invalidatesTags: (_, __, id) => [{ type: APP, id }, APP], + }), + changeAppPermissions: builder.mutation({ + /** + * Changes the permission bits of a marketplace app. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace app id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKETAPP_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: APP, id }], + }), + changeAppOwnership: builder.mutation({ + /** + * Changes the ownership of a marketplace app. + * If set `user` or `group` to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace app id + * @param {string|'-1'} [params.userId] - User id + * @param {string|'-1'} [params.groupId] - Group id + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKETAPP_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: APP, id }, APP], + }), + renameApp: builder.mutation({ + /** + * Renames a marketplace app. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace app id + * @param {string} params.name - The new name + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKETAPP_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: APP, id }, APP], + }), + lockApp: builder.mutation({ + /** + * Locks a MarketPlaceApp. Lock certain actions depending on blocking level. + * - `USE` (1): locks Admin, Manage and Use actions. + * - `MANAGE` (2): locks Manage and Use actions. + * - `ADMIN` (3): locks only Admin actions. + * - `ALL` (4): locks all actions. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace app id + * @param {'1'|'2'|'3'|'4'} params.lock - Lock level + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.MARKETAPP_LOCK + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: APP, id }, APP], + }), + unlockApp: builder.mutation({ + /** + * Unlocks a MarketPlaceApp. + * + * @param {string} id - Marketplace app id + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.MARKETAPP_UNLOCK + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: (_, __, id) => [{ type: APP, id }, APP], + }), + importApp: builder.mutation({ + /** + * Imports a VM or VM Template into the marketplace. + * + * @param {object} params - Request parameters + * @param {string} params.id - VM or VM Template id + * @param {'vm'|'vm-template'} params.resource - Type of resource + * @param {string} params.marketId - Market to import all objects + * @param {boolean} params.associated - If `true`, don't import associated VM templates/images + * @param {string} params.vmname - Selects the name for the new VM Template, if the App contains one + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + queryFn: async (params) => { + const name = ExtraActions.MARKETAPP_IMPORT + const command = { name, ...ExtraCommands[name] } + + return { params, command } + }, + invalidatesTags: [APP], + }), + exportApp: builder.mutation({ + /** + * Exports the marketplace app to the OpenNebula cloud. + * + * @param {object} params - Request parameters + * @param {string} params.id - Marketplace App id + * @param {string} params.name - Image name + * @param {string} params.datastore - Datastore id or name + * @param {string} params.file - File datastore id or name + * @param {string} params.tag - DockerHub image tag (default latest) + * @param {boolean} params.template - Associate with VM template + * @param {boolean} params.associated - If `false`, Do not export associated VM templates/images + * @param {string} params.vmname - The name for the new VM Template, if the App contains one + * @returns {number} Marketplace app id + * @throws Fails when response isn't code 200 + */ + query: async (params) => { + const name = ExtraActions.MARKETAPP_EXPORT + const command = { name, ...ExtraCommands[name] } + + return { params, command } + }, + invalidatesTags: [APP], + }), + }), +}) + +export const { + // Queries + useGetMarketplaceAppQuery, + useLazyGetMarketplaceAppQuery, + useGetMarketplaceAppsQuery, + useLazyGetMarketplaceAppsQuery, + useGetDockerHubTagsQuery, + useLazyGetDockerHubTagsQuery, + + // Mutations + useAllocateAppMutation, + useUpdateAppMutation, + useRemoveAppMutation, + useEnableAppMutation, + useDisableAppMutation, + useChangeAppPermissionsMutation, + useChangeAppOwnershipMutation, + useRenameAppMutation, + useLockAppMutation, + useUnlockAppMutation, + useImportAppMutation, + useExportAppMutation, +} = marketAppApi + +export default marketAppApi diff --git a/src/fireedge/src/client/features/OneApi/network.js b/src/fireedge/src/client/features/OneApi/network.js new file mode 100644 index 0000000000..705ef3c3af --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/network.js @@ -0,0 +1,386 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vn' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { + LockLevel, + FilterFlag, + Permission, + VirtualNetwork, +} from 'client/constants' + +const { VNET } = ONE_RESOURCES + +const vNetworkApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getVNetworks: builder.query({ + /** + * Retrieves information for all or part of the virtual networks in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {VirtualNetwork[]} List of virtual networks + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => [data?.VNET_POOL?.VNET ?? []].flat(), + providesTags: [VNET], + }), + getVNetwork: builder.query({ + /** + * Retrieves information for the virtual network. + * + * @param {object} params - Request params + * @param {string} params.id - Virtual network id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {VirtualNetwork} Get Virtual network identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.VNET ?? {}, + providesTags: (_, __, { id }) => [{ type: VNET, id }], + }), + allocateVnet: builder.mutation({ + /** + * Allocates a new virtual network in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - The string containing the template of the resource on syntax XML + * @param {number|'-1'} params.cluster - The cluster ID. If it's -1, the default one will be used + * @returns {number} The allocated virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VNET], + }), + removeVNet: builder.mutation({ + /** + * Deletes the given virtual network from the pool. + * + * @param {number|string} id - Virtual network id + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.VN_DELETE + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: [VNET], + }), + addRangeToVNet: builder.mutation({ + /** + * Adds address ranges to a virtual network. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {string} params.template - Template of the address ranges to add on syntax XML + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_AR_ADD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + removeRangeFromVNet: builder.mutation({ + /** + * Removes an address range from a virtual network. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {number|string} params.address - ID of the address range to remove + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_AR_RM + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + updateVNetRange: builder.mutation({ + /** + * Updates the attributes of an address range. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {string} params.template - Template of the address ranges to update on syntax XML + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_AR_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + reserveAddress: builder.mutation({ + /** + * Reserve network addresses. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {string} params.template - The third parameter must be + * an OpenNebula ATTRIBUTE=VALUE template, with these values: + * - `SIZE`: Size of the reservation (**Mandatory**) + * - `NAME`: If set, the reservation will be created in a new Virtual Network with this name + * - `AR_ID`: ID of the AR from where to take the addresses + * - `NETWORK_ID`: Instead of creating a new Virtual Network, + * the reservation will be added to the existing virtual network with this ID + * - `MAC`: First MAC address to start the reservation range [MAC, MAC+SIZE) + * - `IP`: First IPv4 address to start the reservation range [IP, IP+SIZE) + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_RESERVE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }], + }), + freeReservedAR: builder.mutation({ + /** + * Frees a reserved address range from a virtual network. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {string} params.range - ID of the address range to free + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_AR_FREE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + holdLease: builder.mutation({ + /** + * Holds a virtual network Lease as used. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {string} params.template - Template of the lease to hold, e.g. `LEASES=[IP=192.168.0.5]` + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_HOLD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }], + }), + releaseLease: builder.mutation({ + /** + * Releases a virtual network Lease on hold. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {string} params.template - Template of the lease to hold, e.g. `LEASES=[IP=192.168.0.5]` + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_RELEASE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }], + }), + updateVNet: builder.mutation({ + /** + * Replaces the virtual network template contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - Virtual network id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }], + }), + changeVNetPermissions: builder.mutation({ + /** + * Changes the permission bits of a virtual network. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual network id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }], + }), + changeVNetOwnership: builder.mutation({ + /** + * Changes the ownership of a virtual network. + * If set to `-1`, the user or group aren't changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual network id + * @param {number|'-1'} params.user - The user id + * @param {number|'-1'} params.group - The group id + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + renameVNet: builder.mutation({ + /** + * Renames a virtual network. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual network id + * @param {string} params.name - The new name + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + lockVNet: builder.mutation({ + /** + * Locks a virtual network. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual network id + * @param {LockLevel} params.lock - Lock level + * @param {boolean} params.test - Checks if the object is already locked to return an error + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VN_LOCK + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + unlockVNet: builder.mutation({ + /** + * Unlocks a virtual network. + * + * @param {string|number} id - Virtual network id + * @returns {number} Virtual network id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.VN_UNLOCK + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNET, id }, VNET], + }), + }), +}) + +export const { + // Queries + useGetVNetworksQuery, + useLazyGetVNetworksQuery, + useGetVNetworkQuery, + useLazyGetVNetworkQuery, + + // Mutations + useAllocateVnetMutation, + useRemoveVNetMutation, + useAddRangeToVNetMutation, + useRemoveRangeFromVNetMutation, + useUpdateVNetRangeMutation, + useReserveAddressMutation, + useFreeReservedARMutation, + useHoldLeaseMutation, + useReleaseLeaseMutation, + useUpdateVNetMutation, + useChangeVNetPermissionsMutation, + useChangeVNetOwnershipMutation, + useRenameVNetMutation, + useLockVNetMutation, + useUnlockVNetMutation, +} = vNetworkApi + +export default vNetworkApi diff --git a/src/fireedge/src/client/features/OneApi/networkTemplate.js b/src/fireedge/src/client/features/OneApi/networkTemplate.js new file mode 100644 index 0000000000..0a5d3e5021 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/networkTemplate.js @@ -0,0 +1,294 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vntemplate' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { FilterFlag, Permission, VNetworkTemplate } from 'client/constants' + +const { VNET, VNTEMPLATE } = ONE_RESOURCES + +const vNetworkTemplateApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getVNTemplates: builder.query({ + /** + * Retrieves information for all or part of the VN template in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {VNetworkTemplate[]} List of virtual network templates + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => + [data?.VNTEMPLATE_POOL?.VNTEMPLATE ?? []].flat(), + providesTags: [VNTEMPLATE], + }), + getVNTemplate: builder.query({ + /** + * Retrieves information for the virtual network template. + * + * @param {object} params - Request params + * @param {string|number} params.id - Virtual network template id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {VNetworkTemplate} Get virtual network template identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.VNTEMPLATE ?? {}, + providesTags: (_, __, { id }) => [{ type: VNTEMPLATE, id }], + }), + allocateVNTemplate: builder.mutation({ + /** + * Allocates a new VN Template in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - A string containing the template of the VN Template on syntax XML + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VNTEMPLATE], + }), + cloneVNTemplate: builder.mutation({ + /** + * Clones an existing VN template. + * + * @param {object} params - Request params + * @param {string} params.id - The ID of the VN template to be cloned + * @param {string} params.name - Name for the new resource + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_CLONE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VNTEMPLATE], + }), + removeVNTemplate: builder.mutation({ + /** + * Deletes the given VN template from the pool. + * + * @param {object} params - Request params + * @param {string} params.id - The ID of the VN template + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VNTEMPLATE], + }), + instantiateVNTemplate: builder.mutation({ + /** + * Instantiates a new Virtual Network from a VN template. + * + * @param {object} params - Request params + * @param {string} params.id - The object id + * @param {string} [params.name] - Name for the new Virtual Network + * @param {string} [params.template] + * - A string containing an extra VN template + * to be merged with the one being instantiated on syntax XML + * @returns {number} The new Virtual Network id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_INSTANTIATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VNET], + }), + updateVNTemplate: builder.mutation({ + /** + * Replaces the VN Template template contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - VN Template id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + providesTags: (_, __, { id }) => [{ type: VNTEMPLATE, id }], + }), + changeVNTemplatePermissions: builder.mutation({ + /** + * Changes the permission bits of a VN Template. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - VN Template id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VNTEMPLATE, id }], + }), + changeVNTemplateOwnership: builder.mutation({ + /** + * Changes the ownership of a VN Template. + * If set `user` or `group` to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - VN Template id + * @param {string|number|'-1'} [params.userId] - User id + * @param {Permission|'-1'} [params.groupId] - Group id + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [ + { type: VNTEMPLATE, id }, + VNTEMPLATE, + ], + }), + renameVNTemplate: builder.mutation({ + /** + * Renames a VN Template. + * + * @param {object} params - Request parameters + * @param {string} params.id - VN Template id + * @param {string} params.name - The new name + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [ + { type: VNTEMPLATE, id }, + VNTEMPLATE, + ], + }), + lockVNTemplate: builder.mutation({ + /** + * Locks a VN Template. Lock certain actions depending on blocking level. + * - `USE` (1): locks Admin, Manage and Use actions. + * - `MANAGE` (2): locks Manage and Use actions. + * - `ADMIN` (3): locks only Admin actions. + * - `ALL` (4): locks all actions. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - VN Template id + * @param {'1'|'2'|'3'|'4'} params.lock - Lock level + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VNTEMPLATE_LOCK + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [ + { type: VNTEMPLATE, id }, + VNTEMPLATE, + ], + }), + unlockVNTemplate: builder.mutation({ + /** + * Unlocks a VN Template. + * + * @param {string|number} id - VN Template id + * @returns {number} VN Template id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.VNTEMPLATE_UNLOCK + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: (_, __, id) => [{ type: VNTEMPLATE, id }, VNTEMPLATE], + }), + }), +}) + +export const { + // Queries + useGetVNTemplateQuery, + useLazyGetVNTemplateQuery, + useGetVNTemplatesQuery, + useLazyGetVNTemplatesQuery, + + // Mutations + useAllocateVNTemplateMutation, + useCloneVNTemplateMutation, + useRemoveVNTemplateMutation, + useInstantiateVNTemplateMutation, + useUpdateVNTemplateMutation, + useChangeVNTemplatePermissionsMutation, + useChangeVNTemplateOwnershipMutation, + useRenameVNTemplateMutation, + useLockVNTemplateMutation, + useUnlockVNTemplateMutation, +} = vNetworkTemplateApi + +export default vNetworkTemplateApi diff --git a/src/fireedge/src/client/features/OneApi/provider.js b/src/fireedge/src/client/features/OneApi/provider.js new file mode 100644 index 0000000000..9cab558df8 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/provider.js @@ -0,0 +1,178 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { + Actions, + Commands, +} from 'server/routes/api/oneprovision/provider/routes' +import { oneApi, DOCUMENT } from 'client/features/OneApi' + +const { PROVIDER, PROVIDER_CONFIG } = DOCUMENT + +const providerApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getProviderConfig: builder.query({ + /** + * Gets provider configuration. + * + * @returns {object} Configuration + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.PROVIDER_CONFIG + const command = { name, ...Commands[name] } + + return { command } + }, + providesTags: [PROVIDER_CONFIG], + }), + getProviders: builder.query({ + /** + * Retrieves information for all providers. + * + * @returns {object[]} List of providers + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.PROVIDER_LIST + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat(), + providesTags: [PROVIDER], + }), + getProvider: builder.query({ + /** + * Retrieves information for the provider. + * + * @param {string} id - Provider id + * @returns {object} Get provider identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.PROVIDER_LIST + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.DOCUMENT ?? {}, + providesTags: (_, __, id) => [{ type: PROVIDER, id }], + async onQueryStarted(id, { dispatch, queryFulfilled }) { + try { + const { data: queryProvider } = await queryFulfilled + + dispatch( + providerApi.util.updateQueryData( + 'getProviders', + undefined, + (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryProvider) + } + ) + ) + } catch {} + }, + }), + getProviderConnection: builder.query({ + /** + * Retrieves connection information for the provider. + * + * @param {string} id - Provider id + * @returns {object} Connection info from the provider identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.PROVIDER_CONNECTION + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + keepUnusedDataFor: 5, + }), + createProvider: builder.mutation({ + /** + * Creates a new provider. + * + * @param {object} params - Request parameters + * @param {object} params.data - Provider configuration + * @returns {object} Object of document created + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVIDER_CREATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [PROVIDER], + }), + updateProvider: builder.mutation({ + /** + * Updates the provider information. + * + * @param {object} params - Request parameters + * @param {string} params.id - Provider id + * @param {string} params.data - Updated data + * @returns {object} Object of document updated + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVIDER_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: PROVIDER, id }, PROVIDER], + }), + deleteProvider: builder.mutation({ + /** + * Deletes the provider. + * + * @param {object} params - Request parameters + * @param {object} params.id - Provider id + * @returns {object} Object of document deleted + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVIDER_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [PROVIDER], + }), + }), +}) + +export const { + // Queries + useGetProviderConfigQuery, + useLazyGetProviderConfigQuery, + useGetProvidersQuery, + useLazyGetProvidersQuery, + useGetProviderQuery, + useLazyGetProviderQuery, + useGetProviderConnectionQuery, + useLazyGetProviderConnectionQuery, + + // Mutations + useCreateProviderMutation, + useUpdateProviderMutation, + useDeleteProviderMutation, +} = providerApi + +export default providerApi diff --git a/src/fireedge/src/client/features/OneApi/provision.js b/src/fireedge/src/client/features/OneApi/provision.js new file mode 100644 index 0000000000..70d959bce1 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/provision.js @@ -0,0 +1,303 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { + Actions, + Commands, +} from 'server/routes/api/oneprovision/provision/routes' +import { oneApi, DOCUMENT } from 'client/features/OneApi' + +const { PROVISION, PROVISION_TEMPLATE, PROVISION_RESOURCES } = DOCUMENT + +const provisionApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getProvisions: builder.query({ + /** + * List all available provisions. + * + * @returns {object[]} List of provision + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.PROVISION_LIST + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat(), + providesTags: [PROVISION], + }), + getProvision: builder.query({ + /** + * Retrieves information for the provision. + * + * @param {string} id - Provision id + * @returns {object} Get provision identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.PROVISION_LIST + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.DOCUMENT ?? {}, + providesTags: (_, __, id) => [{ type: PROVISION, id }], + async onQueryStarted(id, { dispatch, queryFulfilled }) { + try { + const { data: queryProvision } = await queryFulfilled + + dispatch( + provisionApi.util.updateQueryData( + 'getProvisions', + undefined, + (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryProvision) + } + ) + ) + } catch {} + }, + }), + getProvisionTemplates: builder.query({ + /** + * Retrieves information for all the provision templates. + * + * @returns {object[]} List of provision templates + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.PROVISION_DEFAULTS + const command = { name, ...Commands[name] } + + return { command } + }, + providesTags: [PROVISION_TEMPLATE], + }), + getProvisionLog: builder.query({ + /** + * Retrieves debug log for the provision. + * + * @param {string} id - Provision id + * @returns {object} Debug log + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.PROVISION_LOGS + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + }), + getResource: builder.query({ + /** + * Delete the datastore from the provision. + * + * @param {object} params - Request parameters + * @param { + * 'cluster'|'datastore'|'host'|'image'| + * 'network'|'template'|'vntemplate'|'flowtemplate' + * } params.resource - Resource name + * @returns {object[]} List of resources + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVISION_GET_RESOURCE + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => { + // example: { HOST_POOL: { HOST: [1, 2] } } => [1, 2] + const pool = Object.values(data)[0] ?? {} + const resources = Object.values(pool)[0] ?? [] + + return [resources].flat() + }, + providesTags: (_, __, { id, resource }) => { + const provisionResource = PROVISION_RESOURCES[resource.toUpperCase()] + + return [{ type: provisionResource, id }, provisionResource] + }, + }), + createProvision: builder.mutation({ + /** + * Provision a new cluster. + * + * @param {object} params - Request parameters + * @param {object} params.data - Provision configuration + * @returns {object} Object of document created + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVISION_CREATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [PROVISION], + }), + configureProvision: builder.mutation({ + /** + * Configure the provision hosts. + * + * @param {object} params - Request parameters + * @param {string} params.id - Provision id + * @returns {object} Object of document updated + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVISION_CONFIGURE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: PROVISION, id }], + }), + deleteProvision: builder.mutation({ + /** + * Delete the provision and OpenNebula objects. + * + * @param {object} params - Request parameters + * @param {object} params.id - Provision id + * @param {boolean} params.force - Force configure to execute + * @param {boolean} params.cleanup - Delete all vms and images first, then delete the resources + * @returns {object} Object of document deleted + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVISION_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [PROVISION], + }), + removeResource: builder.mutation({ + /** + * Delete the datastore from the provision. + * + * @param {object} params - Request parameters + * @param {string} params.provision - Provision id + * @param {string} params.id - Resource id + * @param { + * 'cluster'|'datastore'|'host'|'image'| + * 'network'|'template'|'vntemplate'|'flowtemplate' + * } params.resource - Resource name + * @returns {object} Object of document deleted + * @throws Fails when response isn't code 200 + */ + query: ({ provision: _, ...params }) => { + const name = Actions.PROVISION_DELETE_RESOURCE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { provision, resource }) => [ + { type: PROVISION, id: provision }, + PROVISION_RESOURCES[resource.toUpperCase()], + ], + }), + configureHost: builder.mutation({ + /** + * Run configuration on the host. + * + * @param {object} params - Request parameters + * @param {string} params.provision - Provision id + * @param {string} params.id - Host id + * @returns {number} - Host id + * @throws Fails when response isn't code 200 + */ + query: ({ provision: _, ...params }) => { + const name = Actions.PROVISION_HOST_CONFIGURE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { provision }) => [ + { type: PROVISION, id: provision }, + PROVISION_RESOURCES.HOST, + ], + }), + addHostToProvision: builder.mutation({ + /** + * Provisions and configures a new host or amount of hosts. + * + * @param {object} params - Request parameters + * @param {string} params.id - Provision id + * @param {number} params.amount - Amount of hosts to add to the provision + * @returns {string} - Provision id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVISION_ADD_HOST + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [ + { type: PROVISION, id }, + PROVISION_RESOURCES.HOST, + ], + }), + addIpToProvision: builder.mutation({ + /** + * Adds more IPs to the provision. + * + * @param {object} params - Request parameters + * @param {string} params.id - Provision id + * @param {number} params.amount - Amount of IPs to add to the provision + * @returns {string} - Provision id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.PROVISION_ADD_HOST + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [ + { type: PROVISION, id }, + PROVISION_RESOURCES.HOST, + ], + }), + }), +}) + +export const { + // Queries + useGetProvisionsQuery, + useLazyGetProvisionsQuery, + useGetProvisionQuery, + useLazyGetProvisionQuery, + useGetProvisionTemplatesQuery, + useLazyGetProvisionTemplatesQuery, + useGetProvisionLogQuery, + useLazyGetProvisionLogQuery, + useGetResourceQuery, + useLazyGetResourceQuery, + + // Mutations + useCreateProvisionMutation, + useConfigureProvisionMutation, + useDeleteProvisionMutation, + useRemoveResourceMutation, + useConfigureHostMutation, + useAddHostToProvisionMutation, + useAddIpToProvisionMutation, +} = provisionApi + +export default provisionApi diff --git a/src/fireedge/src/client/features/OneApi/securityGroup.js b/src/fireedge/src/client/features/OneApi/securityGroup.js new file mode 100644 index 0000000000..60ab103966 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/securityGroup.js @@ -0,0 +1,75 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/secgroup' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { FilterFlag } from 'client/constants' + +const { SECURITYGROUP } = ONE_RESOURCES + +const securityGroupApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getSecGroups: builder.query({ + /** + * Retrieves information for all or part of the security groups in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {Array} List of security groups + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.SECGROUP_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => + [data?.SECURITY_GROUP_POOL?.SECURITY_GROUP ?? []].flat(), + providesTags: [SECURITYGROUP], + }), + getSecGroup: builder.query({ + /** + * Retrieves information for the security group. + * + * @param {object} params - Request params + * @param {string|number} params.id - Security group id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {object} Get security group identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.SECGROUP_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.SECURITY_GROUP ?? {}, + providesTags: (_, __, { id }) => [{ type: SECURITYGROUP, id }], + }), + }), +}) + +export const { + // Queries + useGetSecGroupQuery, + useLazyGetSecGroupQuery, + useGetSecGroupsQuery, + useLazyGetSecGroupsQuery, +} = securityGroupApi + +export default securityGroupApi diff --git a/src/fireedge/src/client/features/OneApi/service.js b/src/fireedge/src/client/features/OneApi/service.js new file mode 100644 index 0000000000..2d8252e86a --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/service.js @@ -0,0 +1,85 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/routes/api/oneflow/service/routes' +import { oneApi, DOCUMENT } from 'client/features/OneApi' +import { Service } from 'client/constants' + +const { SERVICE } = DOCUMENT + +const serviceApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getServices: builder.query({ + /** + * Retrieves information for all the services in the pool. + * + * @returns {Service[]} List of services + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.SERVICE_SHOW + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat(), + providesTags: [SERVICE], + }), + getService: builder.query({ + /** + * Retrieves information for the service. + * + * @param {object} params - Request params + * @param {string} params.id - Service id + * @returns {Service} Get service identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.SERVICE_SHOW + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.DOCUMENT ?? {}, + providesTags: (_, __, { id }) => [{ type: SERVICE, id }], + async onQueryStarted({ id }, { dispatch, queryFulfilled }) { + try { + const { data: queryService } = await queryFulfilled + + dispatch( + serviceApi.util.updateQueryData( + 'getServices', + undefined, + (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryService) + } + ) + ) + } catch {} + }, + }), + }), +}) + +export const { + // Queries + useGetServicesQuery, + useLazyGetServicesQuery, + useGetServiceQuery, + useLazyGetServiceQuery, +} = serviceApi + +export default serviceApi diff --git a/src/fireedge/src/client/features/OneApi/serviceTemplate.js b/src/fireedge/src/client/features/OneApi/serviceTemplate.js new file mode 100644 index 0000000000..58098690ae --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/serviceTemplate.js @@ -0,0 +1,171 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/routes/api/oneflow/template/routes' +import { oneApi, DOCUMENT } from 'client/features/OneApi' +import { ServiceTemplate } from 'client/constants' + +const { SERVICE, SERVICE_TEMPLATE } = DOCUMENT + +const serviceTemplateApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getServiceTemplates: builder.query({ + /** + * Retrieves information for all the service templates in the pool. + * + * @returns {ServiceTemplate[]} List of service templates + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.SERVICE_TEMPLATE_SHOW + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.DOCUMENT_POOL?.DOCUMENT ?? []].flat(), + providesTags: [SERVICE_TEMPLATE], + }), + getServiceTemplate: builder.query({ + /** + * Retrieves information for the service template. + * + * @param {object} params - Request params + * @param {string} params.id - Service template id + * @returns {ServiceTemplate} Get service template identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.SERVICE_TEMPLATE_SHOW + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.DOCUMENT ?? {}, + providesTags: (_, __, { id }) => [{ type: SERVICE_TEMPLATE, id }], + async onQueryStarted({ id }, { dispatch, queryFulfilled }) { + try { + const { data: queryService } = await queryFulfilled + + dispatch( + serviceTemplateApi.util.updateQueryData( + 'getServiceTemplates', + undefined, + (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryService) + } + ) + ) + } catch {} + }, + }), + createServiceTemplate: builder.mutation({ + /** + * Create a new service template. + * + * @param {object} params - Request params + * @param {object} params.template - Service template data in JSON syntax + * @returns {number} Service template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.SERVICE_TEMPLATE_CREATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + providesTags: [SERVICE_TEMPLATE], + }), + updateServiceTemplate: builder.mutation({ + /** + * Updates the service template contents. + * + * @param {object} params - Request params + * @param {string} params.id - Service template id + * @param {object} [params.template] - Service template data + * @returns {number} Service template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.SERVICE_TEMPLATE_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + providesTags: (_, __, { id }) => [{ type: SERVICE_TEMPLATE, id }], + }), + removeServiceTemplate: builder.mutation({ + /** + * Removes a given service template. + * + * @param {object} params - Request params + * @param {string} params.id - Service template id + * @returns {number} Service template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.SERVICE_TEMPLATE_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + providesTags: [SERVICE_TEMPLATE], + }), + instantiateServiceTemplate: builder.mutation({ + /** + * Perform instantiate action on the service template. + * + * @param {object} params - Request params + * @param {string} params.id - Service template id + * @param {object} params.template - Additional parameters to be passed inside `params` + * @returns {number} Service id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + /* + data: { + action: { + perform: 'instantiate', + params: { merge_template: data }, + }, + }, + method: PUT, + url: `/api/${SERVICE_TEMPLATE}/action/${id}`, + */ + const name = Actions.SERVICE_TEMPLATE_ACTION + const command = { name, ...Commands[name] } + + return { params, command } + }, + providesTags: [SERVICE], + }), + }), +}) + +export const { + // Queries + useGetServiceTemplatesQuery, + useLazyGetServiceTemplatesQuery, + useGetServiceTemplateQuery, + useLazyGetServiceTemplateQuery, + + // Mutations + useCreateServiceTemplateMutation, + useUpdateServiceTemplateMutation, + useRemoveServiceTemplateMutation, + useInstantiateServiceTemplateMutation, +} = serviceTemplateApi + +export default serviceTemplateApi diff --git a/src/fireedge/src/client/features/OneApi/socket.js b/src/fireedge/src/client/features/OneApi/socket.js new file mode 100644 index 0000000000..0a0226194b --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/socket.js @@ -0,0 +1,118 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { ThunkDispatch } from 'redux-thunk' +import socketIO, { Socket } from 'socket.io-client' +import { WEBSOCKET_URL, SOCKETS } from 'client/constants' + +/** + * @typedef {object} HookStateData - Event data from hook event STATE + * @property {HookStateMessage} HOOK_MESSAGE - Hook message from OpenNebula API + */ + +/** + * @typedef {object} HookStateMessage - Hook message from OpenNebula API + * @property {'STATE'} HOOK_TYPE - Type of event API + * @property {('VM'|'HOST'|'IMAGE')} HOOK_OBJECT - Type name of the resource + * @property {string} STATE - The state that triggers the hook. + * @property {string} [LCM_STATE] + * - The LCM state that triggers the hook (Only for VM hooks) + * @property {string} [REMOTE_HOST] + * - If ``yes`` the hook will be executed in the host that triggered + * the hook (for Host hooks) or in the host where the VM is running (for VM hooks). + * Not used for Image hooks. + * @property {string} RESOURCE_ID - ID of resource + * @property {object} [VM] - New data of the VM + * @property {object} [HOST] - New data of the HOST + * @property {object} [IMAGE] - New data of the IMAGE + */ + +/** + * Creates a socket. + * + * @param {Socket} path - The path to get our client file from + * @param {Socket} query - Any query parameters in our uri + * @returns {Socket} Socket + */ +const createWebsocket = (path, query) => + socketIO({ + path: `${WEBSOCKET_URL}/${path}`, + query, + autoConnect: false, + timeout: 10_000, + reconnectionAttempts: 5, + }) + +/** + * @param {HookStateData} data - Event data from hook event STATE + * @returns {{name: ('vm'|'host'|'image'), value: object}} + * - Name and new value of resource + */ +const getResourceFromEventState = (data) => { + const { HOOK_OBJECT: name, [name]: value } = data?.HOOK_MESSAGE ?? {} + + return { name: String(name).toLowerCase(), value } +} + +/** + * Creates a function to update the data from socket. + * + * @param {object} params - Parameters + * @param {Function(Function)} params.updateQueryData - Api + * @param {string} params.resource - Resource name + * @returns {function( + * string, + * { dispatch: ThunkDispatch } + * ):Promise} Function to update data from socket + */ +const UpdateFromSocket = + ({ updateQueryData, resource }) => + async ( + id, + { cacheEntryRemoved, cacheDataLoaded, updateCachedData, getState, dispatch } + ) => { + const { zone } = getState().general + const { jwt: token } = getState().auth + + const query = { token, zone, resource: resource.toLowerCase(), id } + const socket = createWebsocket(SOCKETS.HOOKS, query) + + try { + await cacheDataLoaded + + const listener = ({ data } = {}) => { + const { value } = getResourceFromEventState(data) + if (!value) return + + dispatch( + updateQueryData((draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = value) + }) + ) + + updateCachedData((draft) => { + Object.assign(draft, value) + }) + } + + socket.on(SOCKETS.HOOKS, listener) + socket.open() + } catch {} + await cacheEntryRemoved + socket.close() + } + +export { createWebsocket, UpdateFromSocket } diff --git a/src/fireedge/src/client/features/OneApi/system.js b/src/fireedge/src/client/features/OneApi/system.js new file mode 100644 index 0000000000..39b47657b4 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/system.js @@ -0,0 +1,113 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/system' +import { + Actions as SunstoneActions, + Commands as SunstoneCommands, +} from 'server/routes/api/sunstone/routes' +import { changeView } from 'client/features/Auth/actions' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' + +const { SYSTEM } = ONE_RESOURCES + +const systemApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getOneVersion: builder.query({ + /** + * Returns the OpenNebula core version. + * + * @returns {object} The OpenNebula version + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.SYSTEM_VERSION + const command = { name, ...Commands[name] } + + return { command } + }, + providesTags: [{ type: SYSTEM, id: 'version' }], + keepUnusedDataFor: 600, + }), + getOneConfig: builder.query({ + /** + * Returns the OpenNebula configuration. + * + * @returns {object} The loaded oned.conf file + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.SYSTEM_CONFIG + const command = { name, ...Commands[name] } + + return { command } + }, + providesTags: [{ type: SYSTEM, id: 'config' }], + keepUnusedDataFor: 600, + }), + getSunstoneConfig: builder.query({ + /** + * Returns the Sunstone configuration. + * + * @returns {object} The loaded sunstone-server.conf file + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = SunstoneActions.SUNSTONE_CONFIG + const command = { name, ...SunstoneCommands[name] } + + return { command } + }, + providesTags: [{ type: SYSTEM, id: 'sunstone-config' }], + keepUnusedDataFor: 600, + }), + getSunstoneViews: builder.query({ + /** + * Returns the Sunstone configuration for resource tabs. + * + * @returns {object} The loaded sunstone view files + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = SunstoneActions.SUNSTONE_VIEWS + const command = { name, ...SunstoneCommands[name] } + + return { command } + }, + async onQueryStarted(_, { dispatch, queryFulfilled }) { + try { + const { data: views = {} } = await queryFulfilled + dispatch(changeView(Object.keys(views)[0])) + } catch {} + }, + providesTags: [{ type: SYSTEM, id: 'sunstone-views' }], + keepUnusedDataFor: 600, + }), + }), +}) + +export const { + // Queries + useGetOneVersionQuery, + useLazyGetOneVersionQuery, + useGetOneConfigQuery, + useLazyGetOneConfigQuery, + useGetSunstoneConfigQuery, + useLazyGetSunstoneConfigQuery, + useGetSunstoneViewsQuery, + useLazyGetSunstoneViewsQuery, +} = systemApi + +export default systemApi diff --git a/src/fireedge/src/client/features/OneApi/user.js b/src/fireedge/src/client/features/OneApi/user.js new file mode 100644 index 0000000000..6b9cc6ca53 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/user.js @@ -0,0 +1,330 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/user' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { User } from 'client/constants' + +const { USER } = ONE_RESOURCES + +const userApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getUsers: builder.query({ + /** + * Retrieves information for all the users in the pool. + * + * @returns {User[]} List of users + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.USER_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.USER_POOL?.USER ?? []].flat(), + providesTags: [USER], + }), + getUser: builder.query({ + /** + * Retrieves information for the user. + * + * @param {string} id - User id + * @returns {User} Get user identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.USER_INFO + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.USER ?? {}, + providesTags: (_, __, id) => [{ type: USER, id }], + }), + allocateUser: builder.mutation({ + /** + * Allocates a new user in OpenNebula. + * + * @param {object} params - Request parameters + * @param {string} params.username - Username for the new user + * @param {string} params.password - Password for the new user + * @param {string} params.driver - Authentication driver for the new user. + * If it is an empty string, then the default 'core' is used + * @param {string[]} params.group - array of Group IDs. + * **The first ID will be used as the main group.** + * This array can be empty, in which case the default group will be used + * @returns {number} The allocated User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [USER], + }), + updateUser: builder.mutation({ + /** + * Replaces the user template contents. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - User id + * @param {string} params.template - The new user template contents on syntax XML + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }], + }), + removeUser: builder.mutation({ + /** + * Deletes the given user from the pool. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - User id + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }, USER], + }), + changePassword: builder.mutation({ + /** + * Changes the password for the given user. + * + * @param {object} params - Request parameters + * @param {string} params.id - User id + * @param {string} params.password - The new password + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_PASSWD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }], + }), + changeAuthDriver: builder.mutation({ + /** + * Changes the authentication driver and the password for the given user. + * + * @param {object} params - Request parameters + * @param {string} params.id - User id + * @param {string} params.driver - The new authentication driver + * @param {string} [params.password] - The new password. + * If it is an empty string, the password is not changed. + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_CHAUTH + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }], + }), + changeGroup: builder.mutation({ + /** + * Changes the group of the given user. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - User id + * @param {string|number} params.group - New group + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_CHGRP + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }], + async onQueryStarted({ id, group }, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + userApi.util.updateQueryData('getUsers', undefined, (draft) => { + const user = draft.find(({ ID }) => +ID === +id) + user && (user.GID = group) + }) + ) + } catch {} + }, + }), + addToGroup: builder.mutation({ + /** + * Adds the User to a secondary group. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - User id + * @param {string|number} params.group - The Group id of the new group + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_ADDGROUP + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }, USER], + }), + removeFromGroup: builder.mutation({ + /** + * Removes the User from a secondary group. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - User id + * @param {string|number} params.group - The Group id + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_DELGROUP + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }, USER], + }), + enableUser: builder.mutation({ + /** + * Enables a user. + * + * @param {string|number} id - User id + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.USER_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: false }, command } + }, + invalidatesTags: (_, __, id) => [{ type: USER, id }, USER], + }), + disableUser: builder.mutation({ + /** + * Disables a user. + * + * @param {string|number} id - User id + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.USER_ENABLE + const command = { name, ...Commands[name] } + + return { params: { id, enable: false }, command } + }, + invalidatesTags: (_, __, id) => [{ type: USER, id }, USER], + }), + getUserQuota: builder.query({ + /** + * Returns the default user quota limits. + * + * @returns {string} The quota template contents + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.USER_QUOTA_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + }), + updateUserQuota: builder.mutation({ + /** + * Sets the user quota limits. + * + * @param {object} params - Request parameters + * @param {string} params.id - User id + * @param {string} params.template - The new quota template contents on syntax XML + * @returns {number} User id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_QUOTA + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: USER, id }], + }), + updateDefaultUserQuota: builder.mutation({ + /** + * Returns the default user quota limits. + * + * @param {object} params - Request parameters + * @param {string} params.template - The new quota template contents on syntax XML + * @returns {string} The quota template contents + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.USER_QUOTA_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + }), +}) + +export const { + // Queries + useGetUserQuery, + useLazyGetUserQuery, + useGetUsersQuery, + useLazyGetUsersQuery, + useGetUserQuotaQuery, + useLazyGetUserQuotaQuery, + + // Mutations + useAllocateUserMutation, + useUpdateUserMutation, + useRemoveUserMutation, + useChangePasswordMutation, + useChangeAuthDriverMutation, + useChangeGroupMutation, + useAddToGroupMutation, + useRemoveFromGroupMutation, + useEnableUserMutation, + useDisableUserMutation, + useUpdateUserQuotaMutation, + useUpdateDefaultUserQuotaMutation, +} = userApi + +export default userApi diff --git a/src/fireedge/src/client/features/OneApi/vm.js b/src/fireedge/src/client/features/OneApi/vm.js new file mode 100644 index 0000000000..e7dd27f63c --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/vm.js @@ -0,0 +1,883 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vm' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { UpdateFromSocket } from 'client/features/OneApi/socket' +import http from 'client/utils/rest' +import { + LockLevel, + FilterFlag, + Permission, + VM as VmType, +} from 'client/constants' + +const { VM } = ONE_RESOURCES + +const vmApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getVms: builder.query({ + /** + * Retrieves information for all or part of + * the VMs in the pool. + * + * @param {object} params - Request params + * @param {boolean} params.extended - Retrieves information for all or part + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @param {number} [params.state] - VM state to filter by + * - `-2`: Any state, including DONE + * - `-1`: Any state, except DONE + * - `0`: INIT + * - `1`: PENDING + * - `2`: HOLD + * - `3`: ACTIVE + * - `4`: STOPPED + * - `5`: SUSPENDED + * - `6`: DONE + * - `8`: POWEROFF + * - `9`: UNDEPLOYED + * - `10`: CLONING + * - `11`: CLONING_FAILURE + * @param {string} [params.filterByKey] - Filter in KEY=VALUE format + * @returns {VmType[]} List of VMs + * @throws Fails when response isn't code 200 + */ + query: ({ extended = false, ...params } = {}) => { + const name = extended + ? Actions.VM_POOL_INFO_EXTENDED + : Actions.VM_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => [data?.VM_POOL?.VM ?? []].flat(), + providesTags: [VM], + }), + getVm: builder.query({ + /** + * Retrieves information for the virtual machine. + * + * @param {string} id - VM id + * @returns {VmType} Get VM identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.VM_INFO + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.VM ?? {}, + providesTags: (_, __, id) => [{ type: VM, id }], + async onQueryStarted(id, { dispatch, queryFulfilled }) { + try { + const { data: queryVm } = await queryFulfilled + + dispatch( + vmApi.util.updateQueryData('getVms', undefined, (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryVm) + }) + ) + } catch {} + }, + onCacheEntryAdded: UpdateFromSocket({ + updateQueryData: (updateFn) => + vmApi.util.updateQueryData('getVms', undefined, updateFn), + resource: VM.toLowerCase(), + }), + }), + getMonitoring: builder.query({ + /** + * Returns the virtual machine monitoring records. + * + * @param {string|number} id - Virtual machine id + * @returns {string} The monitoring information + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.VM_MONITORING + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + }), + getMonitoringPool: builder.query({ + /** + * Returns all the virtual machine monitoring records. + * + * @param {object} params - Request parameters + * @param {FilterFlag} params.filter - Filter flag + * @param {number|'0'|'-1'} [params.seconds] + * - Retrieve monitor records in the last num seconds + * - `0`: Only the last record. + * - `-1`: All records. + * @returns {string} The monitoring information + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_POOL_MONITORING + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + getAccountingPool: builder.query({ + /** + * Returns the virtual machine history records. + * + * @param {object} params - Request parameters + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {string} The information string + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_POOL_ACCOUNTING + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + getShowbackPool: builder.query({ + /** + * Returns the virtual machine showback records. + * + * @param {object} params - Request parameters + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.startMonth] - First month for the time interval + * @param {number} [params.startYear] - First year for the time interval + * @param {number} [params.endMonth] - Last month for the time interval + * @param {number} [params.endYear] - Last year for the time interval + * @returns {string} The information string + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_POOL_SHOWBACK + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + calculateShowback: builder.query({ + /** + * Processes all the history records, and stores the monthly cost for each VM. + * + * @param {object} params - Request parameters + * @param {number} [params.startMonth] - First month for the time interval + * @param {number} [params.startYear] - First year for the time interval + * @param {number} [params.endMonth] - Last month for the time interval + * @param {number} [params.endYear] - Last year for the time interval + * @returns {''} Empty + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_POOL_CALCULATE_SHOWBACK + const command = { name, ...Commands[name] } + + return { params, command } + }, + }), + allocateVm: builder.mutation({ + /** + * Allocates a new virtual machine in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - A string containing the template of the VM on syntax XML + * @param {boolean} [params.status] - False to create the VM on pending (default), True to create it on hold. + * @returns {number} VM id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VM], + }), + saveAsTemplate: builder.mutation({ + /** + * Clones the VM's source Template, replacing the disks with live snapshots + * of the current disks. The VM capacity and NICs are also preserved. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.name - Template name + * @param {boolean} params.persistent - Make the new images persistent + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + queryFn: async ({ id, name, persistent }) => { + try { + const response = await http.request({ + url: `/api/vm/save/${id}`, + method: 'POST', + data: { name, persistent }, + }) + + return { data: response.data } + } catch (axiosError) { + const { response } = axiosError + + return { error: { status: response?.status, data: response?.data } } + } + }, + }), + deploy: builder.mutation({ + /** + * Initiates the instance of the given VM id on the target host. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.host - The target host id + * @param {boolean} [params.enforce] - If `true`, will enforce the Host capacity isn't over committed. + * @param {string|number} [params.datastore] - The target datastore id. + * It is optional, and can be set to -1 to let OpenNebula choose the datastore + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DEPLOY + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VM], + }), + actionVm: builder.mutation({ + /** + * Submits an action to be performed on a virtual machine. + * + * @param {object} params - Request parameters + * @param {string} params.id - Virtual machine id + * @param {( + * 'terminate-hard'|'terminate'|'undeploy-hard'|'undeploy'| + * 'poweroff-hard'|'poweroff'|'reboot-hard'|'reboot'| + * 'hold'|'release'|'stop'|'suspend'|'resume'|'resched'|'unresched' + * )} params.action - The action name to be performed + * @returns {Response} Response + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_ACTION + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + migrate: builder.mutation({ + /** + * Migrates one virtual machine to the target host. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.host - The target host id + * @param {boolean} [params.live] + * - If `true` we are indicating that we want live migration, otherwise `false`. + * @param {boolean} params.enforce + * - If `true`, will enforce the Host capacity isn't over committed. + * @param {string|number} params.datastore - The target datastore id. + * It is optional, and can be set to -1 to let OpenNebula choose the datastore + * @param {0|1|2} params.type - Migration type: save (0), poweroff (1), poweroff-hard (2) + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_MIGRATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + saveAsDisk: builder.mutation({ + /** + * Sets the disk to be saved in the given image. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.disk - Disk id + * @param {string} params.name - Name for the new Image + * @param {string} [params.type] - Type for the new Image. + * If it is an empty string, then the default one will be used + * @param {string|number} params.snapshot - Id of the snapshot to export. + * If -1 the current image state will be used. + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_SAVEAS + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + createDiskSnapshot: builder.mutation({ + /** + * Takes a new snapshot of the disk image. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.disk - Disk id + * @param {string} params.name - Name for the snapshot + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_SNAP_CREATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + deleteDiskSnapshot: builder.mutation({ + /** + * Deletes a disk snapshot. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.disk - Disk id + * @param {string|number} params.snapshot - Snapshot id + * @returns {number} The id of the snapshot deleted + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_SNAP_CREATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + revertDiskSnapshot: builder.mutation({ + /** + * Reverts disk state to a previously taken snapshot. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.disk - Disk id + * @param {string|number} params.snapshot - Snapshot id + * @returns {number} The snapshot id used + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_SNAP_REVERT + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + renameDiskSnapshot: builder.mutation({ + /** + * Renames a disk snapshot. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.disk - Disk id + * @param {string|number} params.snapshot - Snapshot id + * @param {string} params.name - New snapshot name + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_SNAP_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + attachDisk: builder.mutation({ + /** + * Attaches a new disk to the virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.template + * - A string containing a single DISK vector attribute + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_ATTACH + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + detachDisk: builder.mutation({ + /** + * Detaches a disk from a virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.disk - Disk id + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_DETACH + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + resizeDisk: builder.mutation({ + /** + * Resizes a disk of a virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.disk - Disk id + * @param {string} params.size - The new size string + * - Options to perform action + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_DISK_RESIZE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + attachNic: builder.mutation({ + /** + * Attaches a new network interface to the virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.template + * - A string containing a single NIC vector attribute + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_NIC_ATTACH + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + detachNic: builder.mutation({ + /** + * Detaches a network interface from a virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.nic - NIC id + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_NIC_DETACH + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + changeVmPermissions: builder.mutation({ + /** + * Changes the permission bits of a virtual machine. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + changeVmOwnership: builder.mutation({ + /** + * Changes the ownership bits of a virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {number} params.user - The user id + * @param {number} params.group - The group id + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + renameVm: builder.mutation({ + /** + * Renames a virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.name - The new name + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + async onQueryStarted({ id, name }, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + vmApi.util.updateQueryData('getVms', undefined, (draft) => { + const vm = draft.find(({ ID }) => +ID === +id) + vm && (vm.NAME = name) + }) + ) + } catch {} + }, + }), + createVmSnapshot: builder.mutation({ + /** + * Creates a new virtual machine snapshot. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.name - The new snapshot name + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_SNAP_CREATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + revertVmSnapshot: builder.mutation({ + /** + * Reverts a virtual machine to a snapshot. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.snapshot - The snapshot id + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_SNAP_REVERT + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + deleteVmSnapshot: builder.mutation({ + /** + * Deletes a virtual machine snapshot. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string|number} params.snapshot - The snapshot id + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_SNAP_REVERT + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + resize: builder.mutation({ + /** + * Changes the capacity of the virtual machine. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.template - Template containing the new capacity + * @param {boolean} params.enforce - `true` to enforce the Host capacity isn't over committed + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_RESIZE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + updateUserTemplate: builder.mutation({ + /** + * Replaces the user template contents. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.template - The new user template contents on syntax XML + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + updateConfiguration: builder.mutation({ + /** + * Updates (appends) a set of supported configuration attributes in the VM template. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.template - The new configuration contents on syntax XML + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_CONF_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + recover: builder.mutation({ + /** + * Recovers a stuck VM that is waiting for a driver operation. + * The recovery may be done by failing or succeeding the pending operation. + * + * You need to manually check the vm status on the host, to decide + * if the operation was successful or not. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {0|1|2|3|4} params.operation - Recover operation: + * failure (0), success (1), retry (2), delete (3), delete-recreate (4) + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_RECOVER + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + lockVm: builder.mutation({ + /** + * Locks a Virtual Machine. Lock certain actions depending on blocking level. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {LockLevel} params.level - Lock level + * @param {boolean} params.test - Checks if the object is already locked to return an error + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_LOCK + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + async onQueryStarted({ id, level = '4' }, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + vmApi.util.updateQueryData('getVms', undefined, (draft) => { + const vm = draft.find(({ ID }) => +ID === +id) + vm && (vm.LOCK = { LOCKED: level }) + }) + ) + } catch {} + }, + }), + unlockVm: builder.mutation({ + /** + * Unlocks a Virtual Machine. + * + * @param {string|number} id - Virtual machine id + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.VM_UNLOCK + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: (_, __, id) => [{ type: VM, id }], + async onQueryStarted(id, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + vmApi.util.updateQueryData('getVms', undefined, (draft) => { + const vm = draft.find(({ ID }) => +ID === +id) + vm && (vm.LOCK = undefined) + }) + ) + } catch {} + }, + }), + addScheduledAction: builder.mutation({ + /** + * Add scheduled action to VM. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.template - Template containing the new scheduled action + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_SCHED_ADD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + updateScheduledAction: builder.mutation({ + /** + * Update scheduled VM action. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.schedId - The ID of the scheduled action + * @param {string} params.template - Template containing the updated scheduled action + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_SCHED_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + deleteScheduledAction: builder.mutation({ + /** + * Delete scheduled action from VM. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Virtual machine id + * @param {string} params.schedId - The ID of the scheduled action + * @returns {number} Virtual machine id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_SCHED_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: VM, id }], + }), + }), +}) + +export const { + // Queries + useGetVmsQuery, + useLazyGetVmsQuery, + useGetVmQuery, + useLazyGetVmQuery, + useGetMonitoringQuery, + useLazyGetMonitoringQuery, + useGetMonitoringPoolQuery, + useLazyGetMonitoringPoolQuery, + useGetAccountingPoolQuery, + useLazyGetAccountingPoolQuery, + useGetShowbackPoolQuery, + useLazyGetShowbackPoolQuery, + useCalculateShowbackQuery, + useLazyCalculateShowbackQuery, + + // Mutations + useAllocateVmMutation, + useSaveAsTemplateMutation, + useDeployMutation, + useActionVmMutation, + useMigrateMutation, + useSaveAsDiskMutation, + useCreateDiskSnapshotMutation, + useDeleteDiskSnapshotMutation, + useRevertDiskSnapshotMutation, + useRenameDiskSnapshotMutation, + useAttachDiskMutation, + useDetachDiskMutation, + useResizeDiskMutation, + useAttachNicMutation, + useDetachNicMutation, + useChangeVmPermissionsMutation, + useChangeVmOwnershipMutation, + useRenameVmMutation, + useCreateVmSnapshotMutation, + useRevertVmSnapshotMutation, + useDeleteVmSnapshotMutation, + useResizeMutation, + useUpdateUserTemplateMutation, + useUpdateConfigurationMutation, + useRecoverMutation, + useLockVmMutation, + useUnlockVmMutation, + useAddScheduledActionMutation, + useUpdateScheduledActionMutation, + useDeleteScheduledActionMutation, +} = vmApi + +export default vmApi diff --git a/src/fireedge/src/client/features/OneApi/vmGroup.js b/src/fireedge/src/client/features/OneApi/vmGroup.js new file mode 100644 index 0000000000..f4fc100618 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/vmGroup.js @@ -0,0 +1,75 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vmgroup' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { FilterFlag } from 'client/constants' + +const { VMGROUP } = ONE_RESOURCES + +const vmGroupApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getVMGroups: builder.query({ + /** + * Retrieves information for all or part of the VM groups in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {Array} List of VM groups + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_GROUP_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => [data?.VM_GROUP_POOL?.VM_GROUP ?? []].flat(), + providesTags: (result) => + result + ? [...result.map(({ ID }) => ({ type: VMGROUP, ID })), VMGROUP] + : [VMGROUP], + }), + getVMGroup: builder.query({ + /** + * Retrieves information for the VM group. + * + * @param {object} params - Request params + * @param {string|number} params.id - VM group id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {object} Get VM group identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VM_GROUP_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.VM_GROUP ?? {}, + providesTags: (_, __, arg) => ({ type: VMGROUP, id: arg }), + }), + }), +}) + +export const { + // Queries + useGetVMGroupsQuery, + useLazyGetVMGroupsQuery, + useGetVMGroupQuery, + useLazyGetVMGroupQuery, +} = vmGroupApi diff --git a/src/fireedge/src/client/features/OneApi/vmTemplate.js b/src/fireedge/src/client/features/OneApi/vmTemplate.js new file mode 100644 index 0000000000..db02a3fa44 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/vmTemplate.js @@ -0,0 +1,352 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/template' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { LockLevel, FilterFlag, Permission, VmTemplate } from 'client/constants' + +const { TEMPLATE, VM } = ONE_RESOURCES + +const vmTemplateApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getTemplates: builder.query({ + /** + * Retrieves information for all or part of the Resources in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {VmTemplate[]} List of VM Templates + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => + [data?.VMTEMPLATE_POOL?.VMTEMPLATE ?? []].flat(), + providesTags: [TEMPLATE], + }), + getTemplate: builder.query({ + /** + * Retrieves information for the vm template. + * + * @param {object} params - Request parameters + * @param {string} params.id - Template id + * @param {boolean} params.extended - True to include extended information + * @param {boolean} [params.decrypt] - True to decrypt contained secrets (only admin) + * @returns {VmTemplate} Get template identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.VMTEMPLATE ?? {}, + providesTags: (_, __, { id }) => [{ type: TEMPLATE, id }], + async onQueryStarted({ id }, { dispatch, queryFulfilled }) { + try { + const { data: queryTemplate } = await queryFulfilled + + dispatch( + vmTemplateApi.util.updateQueryData( + 'getTemplates', + undefined, + (draft) => { + const index = draft.findIndex(({ ID }) => +ID === +id) + index !== -1 && (draft[index] = queryTemplate) + } + ) + ) + } catch {} + }, + }), + allocateTemplate: builder.mutation({ + /** + * Allocates a new VM Template in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - A string containing the template on syntax XML + * @returns {number} VM Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [TEMPLATE], + }), + cloneTemplate: builder.mutation({ + /** + * Clones an existing virtual machine template. + * + * @param {object} params - Request params + * @param {number|string} params.id - The ID of the template to be cloned + * @param {string} params.name - Name for the new template + * @param {boolean} params.image + * - `true` to clone the template plus any image defined in DISK. + * The new IMAGE_ID is set into each DISK + * @returns {number} Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_CLONE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [TEMPLATE], + }), + removeTemplate: builder.mutation({ + /** + * Deletes the given template from the pool. + * + * @param {object} params - Request params + * @param {number|string} params.id - Template id + * @param {boolean} params.image - `true` to delete the template plus any image defined in DISK + * @returns {number} Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_DELETE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [TEMPLATE], + }), + instantiateTemplate: builder.mutation({ + /** + * Instantiates a new virtual machine from a template. + * + * @param {object} params - Request params + * @param {number|string} params.id - Template id + * @param {string} params.name - Name for the new VM instance + * @param {boolean} params.hold - True to create it on hold state + * @param {boolean} params.persistent - True to create a private persistent copy + * @param {string} params.template - Extra template to be merged with the one being instantiated + * @returns {number} Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_INSTANTIATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [VM], + }), + updateTemplate: builder.mutation({ + /** + * Replaces the template contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - Template id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: TEMPLATE, id }], + }), + changeTemplatePermissions: builder.mutation({ + /** + * Changes the permission bits of a VM template. + * If set any permission to -1, it's not changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - VM Template id + * @param {Permission|'-1'} params.ownerUse - User use + * @param {Permission|'-1'} params.ownerManage - User manage + * @param {Permission|'-1'} params.ownerAdmin - User administrator + * @param {Permission|'-1'} params.groupUse - Group use + * @param {Permission|'-1'} params.groupManage - Group manage + * @param {Permission|'-1'} params.groupAdmin - Group administrator + * @param {Permission|'-1'} params.otherUse - Other use + * @param {Permission|'-1'} params.otherManage - Other manage + * @param {Permission|'-1'} params.otherAdmin - Other administrator + * @param {boolean} [params.image] - `true` to chmod the template plus any image defined in DISK + * @returns {number} VM Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_CHMOD + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: TEMPLATE, id }], + }), + changeTemplateOwnership: builder.mutation({ + /** + * Changes the ownership bits of a VM template. + * If set to `-1`, the user or group aren't changed. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - VM Template id + * @param {number|'-1'} params.user - The user id + * @param {number|'-1'} params.group - The group id + * @returns {number} VM Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_CHOWN + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: TEMPLATE, id }], + }), + renameTemplate: builder.mutation({ + /** + * Renames a VM template. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - VM Template id + * @param {string} params.name - The new name + * @returns {number} VM Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: TEMPLATE, id }], + async onQueryStarted({ id, name }, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + vmTemplateApi.util.updateQueryData( + 'getTemplates', + undefined, + (draft) => { + const template = draft.find(({ ID }) => +ID === +id) + template && (template.NAME = name) + } + ) + ) + } catch {} + }, + }), + lockTemplate: builder.mutation({ + /** + * Locks a VM Template. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - VM Template id + * @param {LockLevel} params.lock - Lock level + * @param {boolean} params.test - Checks if the object is already locked to return an error + * @returns {number} VM Template id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.TEMPLATE_LOCK + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: TEMPLATE, id }], + async onQueryStarted({ id, level = '4' }, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + vmTemplateApi.util.updateQueryData( + 'getTemplates', + undefined, + (draft) => { + const template = draft.find(({ ID }) => +ID === +id) + template && (template.LOCK = { LOCKED: level }) + } + ) + ) + } catch {} + }, + }), + unlockTemplate: builder.mutation({ + /** + * Unlocks a VM Template. + * + * @param {string|number} id - VM Template id + * @returns {number} VM Template id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.TEMPLATE_UNLOCK + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: (_, __, id) => [{ type: TEMPLATE, id }], + async onQueryStarted(id, { dispatch, queryFulfilled }) { + try { + await queryFulfilled + + dispatch( + vmTemplateApi.util.updateQueryData( + 'getTemplates', + undefined, + (draft) => { + const template = draft.find(({ ID }) => +ID === +id) + template && (template.LOCK = undefined) + } + ) + ) + } catch {} + }, + }), + }), +}) + +export const { + // Queries + useGetTemplatesQuery, + useLazyGetTemplatesQuery, + useGetTemplateQuery, + useLazyGetTemplateQuery, + + // Mutations + useAllocateTemplateMutation, + useCloneTemplateMutation, + useRemoveTemplateMutation, + useInstantiateTemplateMutation, + useUpdateTemplateMutation, + useChangeTemplatePermissionsMutation, + useChangeTemplateOwnershipMutation, + useRenameTemplateMutation, + useLockTemplateMutation, + useUnlockTemplateMutation, +} = vmTemplateApi + +export default vmTemplateApi diff --git a/src/fireedge/src/client/features/OneApi/vrouter.js b/src/fireedge/src/client/features/OneApi/vrouter.js new file mode 100644 index 0000000000..ed4cbe29a5 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/vrouter.js @@ -0,0 +1,72 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/vrouter' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { FilterFlag } from 'client/constants' + +const { VROUTER } = ONE_RESOURCES + +const virtualRouterApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getVRouters: builder.query({ + /** + * Retrieves information for all or part of the virtual routers in the pool. + * + * @param {object} params - Request params + * @param {FilterFlag} [params.filter] - Filter flag + * @param {number} [params.start] - Range start ID + * @param {number} [params.end] - Range end ID + * @returns {Array} List of virtual routers + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VROUTER_POOL_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => [data?.VROUTER_POOL?.VROUTER ?? []].flat(), + providesTags: [VROUTER], + }), + getVRouter: builder.query({ + /** + * Retrieves information for the virtual router. + * + * @param {object} params - Request params + * @param {string|number} params.id - Virtual router id + * @param {boolean} [params.decrypt] - Optional flag to decrypt contained secrets, valid only for admin + * @returns {object} Get virtual router identified by id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.VROUTER_INFO + const command = { name, ...Commands[name] } + + return { params, command } + }, + transformResponse: (data) => data?.VROUTER ?? {}, + providesTags: (_, __, { id }) => [{ type: VROUTER, id }], + }), + }), +}) + +export const { + // Queries + useGetVRouterQuery, + useLazyGetVRouterQuery, + useGetVRoutersQuery, + useLazyGetVRoutersQuery, +} = virtualRouterApi diff --git a/src/fireedge/src/client/features/OneApi/zone.js b/src/fireedge/src/client/features/OneApi/zone.js new file mode 100644 index 0000000000..0e25ae6415 --- /dev/null +++ b/src/fireedge/src/client/features/OneApi/zone.js @@ -0,0 +1,163 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * + * * + * Licensed 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 { Actions, Commands } from 'server/utils/constants/commands/zone' +import { oneApi, ONE_RESOURCES } from 'client/features/OneApi' +import { Zone } from 'client/constants' + +const { ZONE } = ONE_RESOURCES + +const zoneApi = oneApi.injectEndpoints({ + endpoints: (builder) => ({ + getZones: builder.query({ + /** + * Retrieves information for all the zones in the pool. + * + * @returns {Zone[]} List of zones + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.ZONE_POOL_INFO + const command = { name, ...Commands[name] } + + return { command } + }, + transformResponse: (data) => [data?.ZONE_POOL?.ZONE ?? []].flat(), + providesTags: [ZONE], + }), + getZone: builder.query({ + /** + * Retrieves information for the zone. + * + * @param {string} id - Zone id + * @returns {Zone} Get zone identified by id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.ZONE_INFO + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + transformResponse: (data) => data?.ZONE ?? {}, + providesTags: (_, __, { id }) => [{ type: ZONE, id }], + }), + getRaftStatus: builder.query({ + /** + * Retrieves raft status one servers. + * + * @returns {string} The information string + * @throws Fails when response isn't code 200 + */ + query: () => { + const name = Actions.ZONE_RAFTSTATUS + const command = { name, ...Commands[name] } + + return { command } + }, + }), + allocateZone: builder.mutation({ + /** + * Allocates a new zone in OpenNebula. + * + * @param {object} params - Request params + * @param {string} params.template - The string containing the template of the zone on syntax XML + * @returns {number} The allocated zone id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.ZONE_ALLOCATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: [ZONE], + }), + removeZone: builder.mutation({ + /** + * Deletes the given zone from the pool. + * + * @param {number|string} id - Zone id + * @returns {number} Zone id + * @throws Fails when response isn't code 200 + */ + query: (id) => { + const name = Actions.ZONE_DELETE + const command = { name, ...Commands[name] } + + return { params: { id }, command } + }, + invalidatesTags: [ZONE], + }), + updateZone: builder.mutation({ + /** + * Replaces the zone template contents. + * + * @param {object} params - Request params + * @param {number|string} params.id - Zone id + * @param {string} params.template - The new template contents + * @param {0|1} params.replace + * - Update type: + * ``0``: Replace the whole template. + * ``1``: Merge new template with the existing one. + * @returns {number} Zone id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.ZONE_UPDATE + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: ZONE, id }, ZONE], + }), + renameZone: builder.mutation({ + /** + * Renames a zone. + * + * @param {object} params - Request parameters + * @param {string|number} params.id - Zone id + * @param {string} params.name - The new name + * @returns {number} Zone id + * @throws Fails when response isn't code 200 + */ + query: (params) => { + const name = Actions.ZONE_RENAME + const command = { name, ...Commands[name] } + + return { params, command } + }, + invalidatesTags: (_, __, { id }) => [{ type: ZONE, id }, ZONE], + }), + }), +}) + +export const { + // Queries + useGetZonesQuery, + useLazyGetZonesQuery, + useGetZoneQuery, + useLazyGetZoneQuery, + useGetRaftStatusQuery, + useLazyGetRaftStatusQuery, + + // Mutations + useAllocateZoneMutation, + useRemoveZoneMutation, + useUpdateZoneMutation, + useRenameZoneMutation, +} = zoneApi + +export default zoneApi diff --git a/src/fireedge/src/client/hooks/useSocket.js b/src/fireedge/src/client/hooks/useSocket.js index 6a18b61684..ee6dfaee81 100644 --- a/src/fireedge/src/client/hooks/useSocket.js +++ b/src/fireedge/src/client/hooks/useSocket.js @@ -14,101 +14,41 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ import { useCallback } from 'react' -import socketIO from 'socket.io-client' -import { useDispatch } from 'react-redux' - -import { WEBSOCKET_URL, SOCKETS } from 'client/constants' +import { Socket } from 'socket.io-client' import { useAuth } from 'client/features/Auth' import { useGeneral } from 'client/features/General' -import { - eventUpdateResourceState, - getResourceFromEventState, -} from 'client/features/One/socket/actions' -import { updateResourceFromFetch } from 'client/features/One/actions' - -const createWebsocket = (path, query) => - socketIO({ - path: `${WEBSOCKET_URL}/${path}`, - query, - autoConnect: false, - timeout: 10_000, - reconnectionAttempts: 5, - }) +import { createWebsocket } from 'client/features/OneApi/socket' +import { SOCKETS } from 'client/constants' /** * Hook to manage the OpenNebula sockets. * - * @returns {{ - * getHooksSocket: Function, - * getProvisionSocket: Function - * }} - List of functions to interactive with FireEdge sockets + * @returns {{ getProvisionSocket: Function }} - List of functions to interactive with FireEdge sockets */ const useSocket = () => { - const dispatch = useDispatch() const { jwt } = useAuth() const { zone } = useGeneral() /** - * @param {('vm'|'host'|'image')} resource - Resource name - * @param {string} id - Resource id - * @returns {{ connect: Function, disconnect: Function }} - * - Functions to manage the socket connections + * @param {Function} callback - Callback from socket + * @returns {Socket} - Socket */ - const getHooksSocket = useCallback( - ({ resource, id }) => { - const socket = createWebsocket(SOCKETS.HOOKS, { - token: jwt, - zone, - resource, - id, - }) + const getProvisionSocket = useCallback( + (callback) => { + const socket = createWebsocket(SOCKETS.PROVISION, { token: jwt, zone }) + + socket.on(SOCKETS.PROVISION, callback) return { - connect: ({ dataFromFetch, callback }) => { - dataFromFetch && - socket.on(SOCKETS.CONNECT, () => { - // update redux state from data fetched - dispatch( - updateResourceFromFetch({ data: dataFromFetch, resource }) - ) - }) - - socket.on(SOCKETS.HOOKS, ({ data } = {}) => { - // update the list on redux state - dispatch(eventUpdateResourceState(data)) - // return data from event - callback(getResourceFromEventState(data).value) - }) - - socket.connect() - }, - disconnect: () => socket.connected && socket.disconnect(), + on: () => socket.connect(), + off: () => socket.disconnect(), } }, [jwt, zone] ) - /** - * @param {Function} callback - Callback from socket - * @returns {{ on: Function, off: Function }} - * - Functions to manage the socket connections - */ - const getProvisionSocket = useCallback((callback) => { - const socket = createWebsocket(SOCKETS.PROVISION, { token: jwt, zone }) - - socket.on(SOCKETS.PROVISION, callback) - - return { - on: () => socket.connect(), - off: () => socket.disconnect(), - } - }, []) - - return { - getHooksSocket, - getProvisionSocket, - } + return { getProvisionSocket } } export default useSocket diff --git a/src/fireedge/src/client/models/Helper.js b/src/fireedge/src/client/models/Helper.js index d5b2083ee2..82cc31446f 100644 --- a/src/fireedge/src/client/models/Helper.js +++ b/src/fireedge/src/client/models/Helper.js @@ -17,6 +17,7 @@ import { DateTime } from 'luxon' import { j2xParser as Parser, J2xOptions } from 'fast-xml-parser' import { T, UserInputObject, USER_INPUT_TYPES } from 'client/constants' +import { camelCase } from 'client/utils' /** * @param {object} json - JSON @@ -215,6 +216,35 @@ export const getActionsAvailable = (actions = {}, hypervisor = '') => }) .map(([actionName, _]) => actionName) +/** + * Returns the resource info tabs. + * + * @param {object} infoTabs - Info tabs from view yaml + * @param {Function} getTabComponent - Function to get tab component + * @param {string} id - Resource id + * @returns {{ + * id: string, + * name: string, + * renderContent: Function + * }[]} - List of available info tabs for the resource + */ +export const getAvailableInfoTabs = (infoTabs = {}, getTabComponent, id) => + Object.entries(infoTabs) + ?.filter(([_, { enabled } = {}]) => !!enabled) + ?.map(([tabName, tabProps]) => { + const camelName = camelCase(tabName) + const TabContent = getTabComponent?.(camelName) + + return ( + TabContent && { + name: camelName, + id: tabName, + renderContent: () => , + } + ) + }) + ?.filter(Boolean) + /** * * @param {object} list - List of attributes diff --git a/src/fireedge/src/client/models/Image.js b/src/fireedge/src/client/models/Image.js index 4a1b494f14..7f4cb1cb20 100644 --- a/src/fireedge/src/client/models/Image.js +++ b/src/fireedge/src/client/models/Image.js @@ -18,13 +18,13 @@ import { DISK_TYPES, IMAGE_STATES, StateInfo, + Image, } from 'client/constants' /** * Returns the image type. * - * @param {object} image - Image - * @param {number|string} image.TYPE - Type numeric code + * @param {Image} image - Image * @returns {IMAGE_TYPES} - Image type */ export const getType = ({ TYPE } = {}) => @@ -33,8 +33,7 @@ export const getType = ({ TYPE } = {}) => /** * Returns the image state. * - * @param {object} image - Image - * @param {number|string} image.STATE - State code + * @param {Image} image - Image * @returns {StateInfo} - Image state information */ export const getState = ({ STATE } = {}) => IMAGE_STATES[+STATE] @@ -42,8 +41,7 @@ export const getState = ({ STATE } = {}) => IMAGE_STATES[+STATE] /** * Returns the disk type. * - * @param {object} image - Image - * @param {number|string} image.DISK_TYPE - Disk type numeric code + * @param {Image} image - Image * @returns {DISK_TYPES} - Disk type */ export const getDiskType = ({ DISK_TYPE } = {}) => diff --git a/src/fireedge/src/client/models/Marketplace.js b/src/fireedge/src/client/models/Marketplace.js index b8327a33e7..159d76ed77 100644 --- a/src/fireedge/src/client/models/Marketplace.js +++ b/src/fireedge/src/client/models/Marketplace.js @@ -14,13 +14,12 @@ * limitations under the License. * * ------------------------------------------------------------------------- */ import { prettyBytes } from 'client/utils' -import { MARKETPLACE_STATES, StateInfo } from 'client/constants' +import { MARKETPLACE_STATES, StateInfo, Marketplace } from 'client/constants' /** * Returns the marketplace state. * - * @param {object} marketplace - Marketplace - * @param {number|string} marketplace.STATE - Marketplace state numeric code + * @param {Marketplace} marketplace - Marketplace * @returns {StateInfo} Marketplace state information */ export const getState = ({ STATE } = {}) => MARKETPLACE_STATES[+STATE] @@ -28,9 +27,7 @@ export const getState = ({ STATE } = {}) => MARKETPLACE_STATES[+STATE] /** * Returns the marketplace capacity information. * - * @param {object} marketplace - Marketplace - * @param {number|string} marketplace.TOTAL_MB - Total capacity MB available - * @param {number|string} marketplace.USED_MB - Capacity used MB + * @param {Marketplace} marketplace - Marketplace * @returns {{ * percentOfUsed: number, * percentLabel: string @@ -44,8 +41,5 @@ export const getCapacityInfo = ({ TOTAL_MB, USED_MB } = {}) => { percentOfUsed )}%)` - return { - percentOfUsed, - percentLabel, - } + return { percentOfUsed, percentLabel } } diff --git a/src/fireedge/src/client/models/Scheduler.js b/src/fireedge/src/client/models/Scheduler.js index 1f3007df32..9ad716e6da 100644 --- a/src/fireedge/src/client/models/Scheduler.js +++ b/src/fireedge/src/client/models/Scheduler.js @@ -13,9 +13,17 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +/* eslint-disable jsdoc/valid-types */ import { isDate, timeToString } from 'client/models/Helper' import { Tr } from 'client/components/HOC' -import { T, VM_ACTIONS } from 'client/constants' +import { + T, + VM_ACTIONS, + ARGS_TYPES, + PERIOD_TYPES, + ScheduleAction, + CharterOptions, +} from 'client/constants' const { SNAPSHOT_DISK_CREATE, @@ -26,70 +34,6 @@ const { SNAPSHOT_DELETE, } = VM_ACTIONS -/** - * @typedef ScheduledAction - * @property {string} ACTION - Action to execute - * @property {string} ID - Id - * @property {string} TIME - Time - * @property {string} [WARNING] - Warning time - * @property {string} [ARGS] - Arguments separated by comma - * @property {string} [DAYS] - Days that the users wants execute the action. - * List separated by comma. Depend of REPEAT: - * - weekly: 0 (Sunday) to 6 (Saturday) - * - monthly: 1 to 31 - * - yearly: 1 to 365 - * - hourly: each ‘x’ hours - * @property {'0'|'1'|'2'} [END_TYPE] - Way to end the repetition. Can be: - * - never: 0 - * - repetition: 1 - * - date: 2 - * @property {string} [END_VALUE] - End value - * @property {'0'|'1'|'2'|'3'} [REPEAT] - Type of repetition. Can be: - * - weekly: '0', - * - monthly: '1', - * - yearly: '2', - * - hourly: '3', - */ - -/** - * @typedef CharterOptions - * @property {boolean} [edit] - If `true`, the charter can be edited in form - * @property {number|string} execute_after_days - Days to execute the action - * @property {number|string} warn_before_days - Alert a time before the action (in days) - */ - -/** @enum {string} Values to end an action */ -export const END_TYPE_VALUES = { - NEVER: '0', - REPETITION: '1', - DATE: '2', -} - -/** @enum {string} Values to repeat an action */ -export const REPEAT_VALUES = { - WEEKLY: '0', - MONTHLY: '1', - YEARLY: '2', - HOURLY: '3', -} - -/** @enum {string} Argument attributes */ -export const ARGS_TYPES = { - DISK_ID: 'DISK_ID', - NAME: 'NAME', - SNAPSHOT_ID: 'SNAPSHOT_ID', -} - -/** @enum {string} Period type */ -export const PERIOD_TYPES = { - YEARS: 'years', - MONTHS: 'months', - WEEKS: 'weeks', - DAYS: 'days', - HOURS: 'hours', - MINUTES: 'minutes', -} - /** * Checks if time is relative. * @@ -160,7 +104,7 @@ export const timeToSecondsByPeriodicity = (period, time) => /** * Returns information about the repetition of an action: periodicity and the end. * - * @param {ScheduledAction} action - Schedule action + * @param {ScheduleAction} action - Schedule action * @returns {{repeat: string|string[], end: string}} - Periodicity of the action. */ export const getRepeatInformation = (action) => { @@ -209,7 +153,7 @@ export const getRequiredArgsByAction = (action) => { /** * Transforms the arguments from the scheduled action to object. * - * @param {scheduledAction} [scheduledAction] - Schedule action + * @param {ScheduleAction} [scheduleAction] - Schedule action * @returns {object} Arguments in object format */ export const transformStringToArgsObject = ({ ACTION, ARGS = {} } = {}) => { @@ -253,7 +197,7 @@ const getTimeAndPeriodTypeFromCharter = (options, prefix) => { * * @param {[string, CharterOptions][]} charters - Charters from configuration yaml * @param {boolean} relative - If `true`, returns times in relative format - * @returns {ScheduledAction[]} - Scheduled action + * @returns {ScheduleAction[]} - Scheduled action */ export const transformChartersToSchedActions = (charters, relative = false) => { const now = Math.round(Date.now() / 1000) diff --git a/src/fireedge/src/client/models/SecurityGroup.js b/src/fireedge/src/client/models/SecurityGroup.js index 3bc5ad5eda..74c4f4102d 100644 --- a/src/fireedge/src/client/models/SecurityGroup.js +++ b/src/fireedge/src/client/models/SecurityGroup.js @@ -19,23 +19,9 @@ import { RULE_TYPE_STRING, ICMP_STRING, ICMP_V6_STRING, + SecurityGroupRule, } from 'client/constants' -/** - * @typedef {object} SecurityGroupRule - * @property {number|string} SECURITY_GROUP_ID - ID - * @property {string} SECURITY_GROUP_NAME - Name - * @property {string} PROTOCOL - Protocol - * @property {string} RULE_TYPE - Rule type - * @property {number|string} ICMP_TYPE - ICMP type - * @property {number|string} [ICMPv6_TYPE] - ICMP v6 type - * @property {number|string} [RANGE] - Range - * @property {number|string} [NETWORK_ID] - Network id - * @property {number|string} [SIZE] - Network size - * @property {string} [IP] - Network IP - * @property {string} [MAC] - Network MAC - */ - /** * Converts a security group attributes into a readable format. * diff --git a/src/fireedge/src/client/models/VirtualMachine.js b/src/fireedge/src/client/models/VirtualMachine.js index bf1bc4caea..0a7c72becd 100644 --- a/src/fireedge/src/client/models/VirtualMachine.js +++ b/src/fireedge/src/client/models/VirtualMachine.js @@ -28,14 +28,21 @@ import { HISTORY_ACTIONS, HYPERVISORS, StateInfo, + VM, + Disk, + Nic, + NicAlias, + ScheduleAction, + HistoryRecord, + Snapshot, } from 'client/constants' /** * This function removes, from the given list, * the Virtual machines in state DONE. * - * @param {Array} vms - List of virtual machines - * @returns {Array} Clean list of vms with done state + * @param {VM[]} vms - List of virtual machines + * @returns {VM[]} Clean list of vms with done state */ export const filterDoneVms = (vms = []) => vms.filter(({ STATE }) => VM_STATES[STATE]?.name !== STATES.DONE) @@ -47,15 +54,15 @@ export const filterDoneVms = (vms = []) => export const getHistoryAction = (action) => HISTORY_ACTIONS[+action] /** - * @param {object} vm - Virtual machine - * @returns {object} History records from resource + * @param {VM} vm - Virtual machine + * @returns {HistoryRecord[]} History records from resource */ export const getHistoryRecords = (vm) => [vm?.HISTORY_RECORDS?.HISTORY ?? []].flat() /** - * @param {object} vm - Virtual machine - * @returns {object} Last history record from resource + * @param {VM} vm - Virtual machine + * @returns {HistoryRecord} Last history record from resource */ export const getLastHistory = (vm) => { const records = getHistoryRecords(vm) @@ -64,7 +71,7 @@ export const getLastHistory = (vm) => { } /** - * @param {object} vm - Virtual machine + * @param {VM} vm - Virtual machine * @returns {string} Resource type: VR, FLOW or VM */ export const getType = (vm) => @@ -75,20 +82,20 @@ export const getType = (vm) => : 'VM' /** - * @param {object} vm - Virtual machine + * @param {VM} vm - Virtual machine * @returns {string} Resource hypervisor */ export const getHypervisor = (vm) => String(getLastHistory(vm)?.VM_MAD).toLowerCase() /** - * @param {object} vm - Virtual machine + * @param {VM} vm - Virtual machine * @returns {boolean} If the hypervisor is vCenter */ export const isVCenter = (vm) => getHypervisor(vm) === HYPERVISORS.vcenter /** - * @param {object} vm - Virtual machine + * @param {VM} vm - Virtual machine * @returns {StateInfo} State information from resource */ export const getState = (vm) => { @@ -99,8 +106,8 @@ export const getState = (vm) => { } /** - * @param {object} vm - Virtual machine - * @returns {Array} List of disks from resource + * @param {VM} vm - Virtual machine + * @returns {Disk[]} List of disks from resource */ export const getDisks = (vm) => { const { TEMPLATE = {}, MONITORING = {}, SNAPSHOTS = {} } = vm ?? {} @@ -152,13 +159,13 @@ export const getDisks = (vm) => { } /** - * @param {object} vm - Virtual machine + * @param {VM} vm - Virtual machine * @param {object} [options] - Options * @param {boolean} [options.groupAlias] * - Create ALIAS attribute with result to mapping NIC_ALIAS and ALIAS_IDS * @param {boolean} [options.securityGroupsFromTemplate] * - Create SECURITY_GROUPS attribute with rules from TEMPLATE.SECURITY_GROUP_RULE - * @returns {object[]} List of nics from resource + * @returns {Nic[]} List of nics from resource */ export const getNics = (vm, options = {}) => { const { groupAlias = false, securityGroupsFromTemplate = false } = options @@ -204,8 +211,8 @@ export const getNics = (vm, options = {}) => { } /** - * @param {object} vm - Virtual machine - * @returns {Array} List of ips from resource + * @param {VM} vm - Virtual machine + * @returns {string[]} List of ips from resource */ export const getIps = (vm) => { const getIpsFromNic = (nic) => @@ -215,8 +222,8 @@ export const getIps = (vm) => { } /** - * @param {object} vm - Virtual machine - * @returns {{ nics: Array, alias: Array }} Lists of nics and alias from resource + * @param {VM} vm - Virtual machine + * @returns {{ nics: Nic[], alias: NicAlias[] }} Lists of nics and alias from resource */ export const splitNicAlias = (vm) => getNics(vm).reduce( @@ -229,8 +236,8 @@ export const splitNicAlias = (vm) => ) /** - * @param {object} vm - Virtual machine - * @returns {Array} List of snapshots from resource + * @param {VM} vm - Virtual machine + * @returns {Snapshot[]} List of snapshots from resource */ export const getSnapshotList = (vm) => { const { TEMPLATE = {} } = vm ?? {} @@ -239,8 +246,8 @@ export const getSnapshotList = (vm) => { } /** - * @param {object} vm - Virtual machine - * @returns {Array} List of schedule actions from resource + * @param {VM} vm - Virtual machine + * @returns {ScheduleAction[]} List of schedule actions from resource */ export const getScheduleActions = (vm) => { const { STIME: vmStartTime, TEMPLATE = {} } = vm ?? {} diff --git a/src/fireedge/src/client/models/VirtualNetwork.js b/src/fireedge/src/client/models/VirtualNetwork.js index 34f93d4038..b3e20a9b0f 100644 --- a/src/fireedge/src/client/models/VirtualNetwork.js +++ b/src/fireedge/src/client/models/VirtualNetwork.js @@ -13,11 +13,12 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ +import { VirtualNetwork } from 'client/constants' + /** * Returns the total number of leases in the virtual network. * - * @param {object} virtualNetwork - Virtual network - * @param {object} virtualNetwork.AR_POOL - Address range pool + * @param {VirtualNetwork} virtualNetwork - Virtual network * @returns {number} Total leases */ export const getTotalLeases = ({ AR_POOL } = {}) => { @@ -29,12 +30,8 @@ export const getTotalLeases = ({ AR_POOL } = {}) => { /** * Returns the virtual network leases information. * - * @param {object} virtualNetwork - Virtual network - * @param {object} virtualNetwork.USED_LEASES - Used network leases - * @returns {{ - * percentOfUsed: number, - * percentLabel: string - * }} Leases information + * @param {VirtualNetwork} virtualNetwork - Virtual network + * @returns {{ percentOfUsed: number, percentLabel: string }} Leases information */ export const getLeasesInfo = ({ USED_LEASES, ...virtualNetwork } = {}) => { const totalLeases = getTotalLeases(virtualNetwork) diff --git a/src/fireedge/src/client/providers/socketProvider.js b/src/fireedge/src/client/providers/socketProvider.js deleted file mode 100644 index 304d9453a0..0000000000 --- a/src/fireedge/src/client/providers/socketProvider.js +++ /dev/null @@ -1,77 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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 jsdoc/require-jsdoc */ -import { createContext, useEffect, useState } from 'react' -import PropTypes from 'prop-types' - -import socketIO from 'socket.io-client' -import { useSelector, useDispatch } from 'react-redux' - -import { WEBSOCKET_URL, SOCKETS } from 'client/constants' -import * as sockets from 'client/features/One/socket/actions' - -const createProvisionWebsocket = (query) => - socketIO({ - path: `${WEBSOCKET_URL}/${SOCKETS.PROVISION}`, - query, - }) - -export const SocketContext = createContext(null) - -const SocketProvider = ({ children }) => { - const [socket, setSocket] = useState({}) - - const dispatch = useDispatch() - const { jwt, zone } = useSelector((state) => ({ - zone: state?.general?.zone, - jwt: state?.auth?.jwt, - })) - - useEffect(() => { - if (!jwt) return - - const client = createProvisionWebsocket({ token: jwt, zone }) - setSocket(client) - - client.on(SOCKETS.PROVISION, (data) => { - dispatch(sockets.onCreateProvision(data)) - }) - - return () => { - setSocket(null) - client?.disconnect() - } - }, [jwt, zone]) - - return ( - - {children} - - ) -} - -SocketProvider.propTypes = { - children: PropTypes.oneOfType([ - PropTypes.node, - PropTypes.arrayOf(PropTypes.node), - ]), -} - -SocketProvider.defaultProps = { - children: undefined, -} - -export default SocketProvider diff --git a/src/fireedge/src/client/store/index.js b/src/fireedge/src/client/store/index.js index a0c34ee7ca..0b64f7f8da 100644 --- a/src/fireedge/src/client/store/index.js +++ b/src/fireedge/src/client/store/index.js @@ -13,37 +13,36 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ -import { - configureStore, - getDefaultMiddleware, - EnhancedStore, -} from '@reduxjs/toolkit' -import thunkMiddleware from 'redux-thunk' +import { configureStore, EnhancedStore } from '@reduxjs/toolkit' +import { setupListeners } from '@reduxjs/toolkit/query/react' -import rootReducer from 'client/store/reducers' import { isDevelopment } from 'client/utils' +import * as Auth from 'client/features/Auth/slice' +import * as General from 'client/features/General/slice' +import { oneApi } from 'client/features/OneApi' + /** * @param {object} props - Props * @param {object} props.initState - Initial state - * @param {*} props.services - Services * @returns {{ store: EnhancedStore }} Configured Redux Store */ -export const createStore = ({ initState = {}, services }) => { - const middleware = getDefaultMiddleware({ - immutableCheck: true, - serializableCheck: false, - thunk: false, - }) - - middleware.push(thunkMiddleware.withExtraArgument({ services })) - +export const createStore = ({ initState = {} }) => { const store = configureStore({ - reducer: rootReducer, + reducer: { + [Auth.name]: Auth.reducer, + [General.name]: General.reducer, + [oneApi.reducerPath]: oneApi.reducer, + }, devTools: isDevelopment(), - middleware, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + immutableCheck: true, + }).concat(oneApi.middleware), preloadedState: initState, }) + setupListeners(store.dispatch) + return { store } } diff --git a/src/fireedge/src/client/store/reducers.js b/src/fireedge/src/client/store/reducers.js index c7cc93ba8b..a2c46410f9 100644 --- a/src/fireedge/src/client/store/reducers.js +++ b/src/fireedge/src/client/store/reducers.js @@ -16,12 +16,12 @@ const { combineReducers } = require('redux') const Auth = require('client/features/Auth/slice') const General = require('client/features/General/slice') -const One = require('client/features/One/slice') +const { oneApi } = require('client/features/OneApi') const rootReducer = combineReducers({ general: General.reducer, auth: Auth.reducer, - one: One.reducer, + [oneApi.reducerPath]: oneApi.reducer, }) module.exports = rootReducer diff --git a/src/fireedge/src/client/utils/helpers.js b/src/fireedge/src/client/utils/helpers.js index 3125ee22d8..fa3d14a3ad 100644 --- a/src/fireedge/src/client/utils/helpers.js +++ b/src/fireedge/src/client/utils/helpers.js @@ -93,7 +93,7 @@ export const encodeBase64 = (string, defaultValue = '') => { * Converts a long string of units into a readable format e.g KB, MB, GB, TB, YB. * * @param {number|string} value - The quantity of units. - * @param {string} unit - The unit of value. + * @param {'KB'|'MB'|'GB'|'TB'|'PB'|'EB'|'ZB'|'YB'} unit - The unit of value. Defaults in KB * @param {number} fractionDigits * - Number of digits after the decimal point. Must be in the range 0 - 20, inclusive * @returns {string} Returns an string displaying sizes for humans. diff --git a/src/fireedge/src/client/utils/request.js b/src/fireedge/src/client/utils/request.js index 933f64f0fa..56231d5198 100644 --- a/src/fireedge/src/client/utils/request.js +++ b/src/fireedge/src/client/utils/request.js @@ -16,57 +16,69 @@ import { AxiosRequestConfig, Method } from 'axios' import { defaults } from 'server/utils/constants' -const { from: resourceFrom } = defaults +const { from: fromTypes } = defaults const getQueries = (params) => Object.entries(params) - ?.filter( - ([, { from, value }]) => - from === resourceFrom.query && value !== undefined + ?.filter(([, { from }]) => from === fromTypes.query) + ?.filter(([, { value }]) => value !== undefined) + ?.reduce( + (acc, [name, { value }]) => ({ ...acc, [name]: encodeURI(value) }), + {} + ) + +const replacePathWithResources = (path = '', params) => + Object.entries(params) + ?.filter(([, { from }]) => from === fromTypes.resource) + ?.reduce( + (replacedPath, [name, { value = '' }]) => + replacedPath.replace(new RegExp(`:${name}(\\??)`), value), + path ) - ?.map(([name, { value }]) => `${name}=${encodeURI(value)}`) - ?.join('&') const getResources = (params) => Object.values(params) - ?.filter(({ from }) => from === resourceFrom.resource) + ?.filter(({ from }) => from === fromTypes.resource) ?.map(({ value }) => value) ?.join('/') const getDataBody = (params) => Object.entries(params) - ?.filter(([, { from }]) => from === resourceFrom.postBody) + ?.filter(([, { from }]) => from === fromTypes.postBody) ?.reduce((acc, [name, { value }]) => ({ ...acc, [name]: value }), {}) /** * @param {object} data - Data for the request * @param {object} command - Command request - * @param {object} command.name - Command name + * @param {string} command.name - Command name + * @param {string} [command.path] - Path to replace with resources * @param {Method} command.httpMethod - Method http * @param {object} command.params - Params to map * @returns {AxiosRequestConfig} Request configuration */ export const requestConfig = (data, command) => { if (command === undefined) throw new Error('command not exists') - const { name, httpMethod, params = {} } = command + const { name, path, httpMethod, params = {} } = command /* Spread 'from' values in current params */ const mappedParams = Object.entries(params)?.reduce( (result, [paraName, { from }]) => ({ ...result, - [paraName]: { from, value: data[paraName] }, + [paraName]: { from, value: data?.[paraName] }, }), {} ) const queries = getQueries(mappedParams) - const resources = getResources(mappedParams) const body = getDataBody(mappedParams) - const url = `/api/${name.replace('.', '/')}` + const url = path + ? `/api${replacePathWithResources(path, mappedParams)}` + : `/api/${name.replace('.', '/')}/${getResources(mappedParams)}` return { - url: `${url}/${resources}?${queries}`, + url, + params: queries, data: body, method: httpMethod, } diff --git a/src/fireedge/src/client/utils/rest.js b/src/fireedge/src/client/utils/rest.js index bbc703f996..20ef07b4b2 100644 --- a/src/fireedge/src/client/utils/rest.js +++ b/src/fireedge/src/client/utils/rest.js @@ -16,9 +16,7 @@ import axios, { AxiosRequestConfig, AxiosResponse } from 'axios' import { httpCodes } from 'server/utils/constants' -import { messageTerminal } from 'server/utils/general' - -import { findStorageData, isDevelopment } from 'client/utils' +import { findStorageData } from 'client/utils' import { T, JWT_NAME, APP_URL } from 'client/constants' const http = axios.create({ baseURL: APP_URL }) @@ -47,16 +45,6 @@ http.interceptors.response.use( return typeof response === 'string' ? response.data.json() : response.data } - if (response.status === httpCodes.unauthorized.id) { - const configErrorParser = { - color: 'red', - error: response?.data?.message ?? response?.statusText, - message: 'Error request: %s', - } - - isDevelopment() && messageTerminal(configErrorParser) - } - return Promise.reject(response) }, (error) => error @@ -69,3 +57,5 @@ export const RestClient = { */ request: (options) => http.request(options), } + +export default http diff --git a/src/fireedge/src/server/routes/api/marketapp/basepath.js b/src/fireedge/src/server/routes/api/marketapp/basepath.js deleted file mode 100644 index 87d527994f..0000000000 --- a/src/fireedge/src/server/routes/api/marketapp/basepath.js +++ /dev/null @@ -1,17 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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. * - * ------------------------------------------------------------------------- */ - -module.exports = 'marketapp' diff --git a/src/fireedge/src/server/routes/api/marketapp/functions.js b/src/fireedge/src/server/routes/api/marketapp/functions.js index c2f9dfdb9b..a66c4a5e99 100644 --- a/src/fireedge/src/server/routes/api/marketapp/functions.js +++ b/src/fireedge/src/server/routes/api/marketapp/functions.js @@ -109,23 +109,22 @@ const exportApp = ( } /** - * Import the marketplace VM or VM TEPLATE to the OpenNebula cloud. + * Import the marketplace VM or VM TEMPLATE to the OpenNebula cloud. * * @param {object} res - http response * @param {Function} next - express stepper * @param {object} params - params of http request - * @param {number} [params.vmId] - vm id - * @param {number} [params.templateId] - template id + * @param {string} [params.id] - Resource id + * @param {string} [params.resource] - Resource name * @param {number} [params.marketId] - market id * @param {string} [params.associated=''] - associated resource * @param {number} [params.vmname] - vm name */ const importMarket = (res = {}, next = defaultEmptyFunction, params = {}) => { let rtn = httpBadRequest - const { vmId, templateId, marketId, associated, vmname } = params - const resource = vmId ? 'vm' : 'vm-template' - const id = vmId || templateId - if (id) { + const { resource, id, marketId, associated, vmname } = params + + if (id && ['vm', 'vm-template'].includes(params.resource)) { let message = '' const paramsCommand = [resource, 'import', `${id}`] diff --git a/src/fireedge/src/server/routes/api/marketapp/index.js b/src/fireedge/src/server/routes/api/marketapp/index.js index 7705843ecc..9820486b4f 100644 --- a/src/fireedge/src/server/routes/api/marketapp/index.js +++ b/src/fireedge/src/server/routes/api/marketapp/index.js @@ -21,12 +21,7 @@ const { getDockerTags, } = require('server/routes/api/marketapp/functions') -const { - MARKETAPP_EXPORT, - MARKETAPP_VMIMPORT, - MARKETAPP_TEMPLATEIMPORT, - MARKETAPP_DOCKERTAGS, -} = Actions +const { MARKETAPP_EXPORT, MARKETAPP_IMPORT, MARKETAPP_DOCKERTAGS } = Actions module.exports = [ { @@ -34,11 +29,7 @@ module.exports = [ action: exportApp, }, { - ...Commands[MARKETAPP_VMIMPORT], - action: importMarket, - }, - { - ...Commands[MARKETAPP_TEMPLATEIMPORT], + ...Commands[MARKETAPP_IMPORT], action: importMarket, }, { diff --git a/src/fireedge/src/server/routes/api/marketapp/routes.js b/src/fireedge/src/server/routes/api/marketapp/routes.js index 97444247c7..e335c60992 100644 --- a/src/fireedge/src/server/routes/api/marketapp/routes.js +++ b/src/fireedge/src/server/routes/api/marketapp/routes.js @@ -17,21 +17,20 @@ const { httpMethod, from: fromData, -} = require('server/utils/constants/defaults') -const MARKETAPP = require('server/routes/api/marketapp/basepath') +} = require('../../../utils/constants/defaults') const { POST, GET } = httpMethod -const basepath = `/${MARKETAPP}` const { query, resource, postBody } = fromData + +const basepath = '/marketapp' + const MARKETAPP_EXPORT = 'marketapp.export' -const MARKETAPP_VMIMPORT = 'marketapp.vmimport' -const MARKETAPP_TEMPLATEIMPORT = 'marketapp.templateimport' +const MARKETAPP_IMPORT = 'marketapp.import' const MARKETAPP_DOCKERTAGS = 'marketapp.dockertags' const Actions = { MARKETAPP_EXPORT, - MARKETAPP_VMIMPORT, - MARKETAPP_TEMPLATEIMPORT, + MARKETAPP_IMPORT, MARKETAPP_DOCKERTAGS, } @@ -69,31 +68,15 @@ module.exports = { }, }, }, - [MARKETAPP_VMIMPORT]: { - path: `${basepath}/vmimport/:vmId`, + [MARKETAPP_IMPORT]: { + path: `${basepath}/import/:resource/:id`, httpMethod: POST, auth: true, params: { - vmId: { + id: { from: resource, }, - associated: { - from: postBody, - }, - marketId: { - from: postBody, - }, - vmname: { - from: postBody, - }, - }, - }, - [MARKETAPP_TEMPLATEIMPORT]: { - path: `${basepath}/templateimport/:templateId`, - httpMethod: POST, - auth: true, - params: { - templateId: { + resource: { from: resource, }, associated: { diff --git a/src/fireedge/src/server/routes/api/oneflow/index.js b/src/fireedge/src/server/routes/api/oneflow/index.js index 52cd2186ec..0438a48823 100644 --- a/src/fireedge/src/server/routes/api/oneflow/index.js +++ b/src/fireedge/src/server/routes/api/oneflow/index.js @@ -52,11 +52,11 @@ const { } = ActionsService const { - SERVICETEMPLATE_SHOW, - SERVICETEMPLATE_ACTION, - SERVICETEMPLATE_CREATE, - SERVICETEMPLATE_UPDATE, - SERVICETEMPLATE_DELETE, + SERVICE_TEMPLATE_SHOW, + SERVICE_TEMPLATE_ACTION, + SERVICE_TEMPLATE_CREATE, + SERVICE_TEMPLATE_UPDATE, + SERVICE_TEMPLATE_DELETE, } = ActionsTemplate const services = [ @@ -96,23 +96,23 @@ const services = [ const template = [ { - ...CommandsTemplate[SERVICETEMPLATE_SHOW], + ...CommandsTemplate[SERVICE_TEMPLATE_SHOW], action: serviceTemplate, }, { - ...CommandsTemplate[SERVICETEMPLATE_ACTION], + ...CommandsTemplate[SERVICE_TEMPLATE_ACTION], action: serviceTemplateAction, }, { - ...CommandsTemplate[SERVICETEMPLATE_CREATE], + ...CommandsTemplate[SERVICE_TEMPLATE_CREATE], action: serviceTemplateCreate, }, { - ...CommandsTemplate[SERVICETEMPLATE_UPDATE], + ...CommandsTemplate[SERVICE_TEMPLATE_UPDATE], action: serviceTemplateUpdate, }, { - ...CommandsTemplate[SERVICETEMPLATE_DELETE], + ...CommandsTemplate[SERVICE_TEMPLATE_DELETE], action: serviceTemplateDelete, }, ] diff --git a/src/fireedge/src/server/routes/api/oneflow/service/routes.js b/src/fireedge/src/server/routes/api/oneflow/service/routes.js index 0c18c253f5..63a8acff04 100644 --- a/src/fireedge/src/server/routes/api/oneflow/service/routes.js +++ b/src/fireedge/src/server/routes/api/oneflow/service/routes.js @@ -17,12 +17,11 @@ const { httpMethod, from: fromData, -} = require('server/utils/constants/defaults') -const { SERVICE } = require('server/routes/api/oneflow/basepath') +} = require('../../../../utils/constants/defaults') -const basepath = `/${SERVICE}` const { GET, POST, DELETE, PUT } = httpMethod const { resource, postBody } = fromData +const basepath = '/service' const SERVICE_SHOW = 'service.show' const SERVICE_ADD_ACTION = 'service.addaction' diff --git a/src/fireedge/src/server/routes/api/oneflow/template/routes.js b/src/fireedge/src/server/routes/api/oneflow/template/routes.js index 6f9ea22ed1..e177f6f163 100644 --- a/src/fireedge/src/server/routes/api/oneflow/template/routes.js +++ b/src/fireedge/src/server/routes/api/oneflow/template/routes.js @@ -17,31 +17,30 @@ const { httpMethod, from: fromData, -} = require('server/utils/constants/defaults') -const { SERVICE_TEMPLATE } = require('server/routes/api/oneflow/basepath') +} = require('../../../../utils/constants/defaults') const { GET, POST, DELETE, PUT } = httpMethod -const basepath = `/${SERVICE_TEMPLATE}` const { resource, postBody } = fromData +const basepath = '/service_template' -const SERVICETEMPLATE_SHOW = 'servicetemplate.show' -const SERVICETEMPLATE_ACTION = 'servicetemplate.action' -const SERVICETEMPLATE_CREATE = 'servicetemplate.create' -const SERVICETEMPLATE_UPDATE = 'servicetemplate.update' -const SERVICETEMPLATE_DELETE = 'servicetemplate.delete' +const SERVICE_TEMPLATE_SHOW = 'servicetemplate.show' +const SERVICE_TEMPLATE_ACTION = 'servicetemplate.action' +const SERVICE_TEMPLATE_CREATE = 'servicetemplate.create' +const SERVICE_TEMPLATE_UPDATE = 'servicetemplate.update' +const SERVICE_TEMPLATE_DELETE = 'servicetemplate.delete' const Actions = { - SERVICETEMPLATE_SHOW, - SERVICETEMPLATE_ACTION, - SERVICETEMPLATE_CREATE, - SERVICETEMPLATE_UPDATE, - SERVICETEMPLATE_DELETE, + SERVICE_TEMPLATE_SHOW, + SERVICE_TEMPLATE_ACTION, + SERVICE_TEMPLATE_CREATE, + SERVICE_TEMPLATE_UPDATE, + SERVICE_TEMPLATE_DELETE, } module.exports = { Actions, Commands: { - [SERVICETEMPLATE_SHOW]: { + [SERVICE_TEMPLATE_SHOW]: { path: `${basepath}/:id`, httpMethod: GET, auth: true, @@ -51,7 +50,7 @@ module.exports = { }, }, }, - [SERVICETEMPLATE_ACTION]: { + [SERVICE_TEMPLATE_ACTION]: { path: `${basepath}/action/:id`, httpMethod: POST, auth: true, @@ -64,7 +63,7 @@ module.exports = { }, }, }, - [SERVICETEMPLATE_CREATE]: { + [SERVICE_TEMPLATE_CREATE]: { path: `${basepath}`, httpMethod: POST, auth: true, @@ -74,7 +73,7 @@ module.exports = { }, }, }, - [SERVICETEMPLATE_UPDATE]: { + [SERVICE_TEMPLATE_UPDATE]: { path: `${basepath}/:id`, httpMethod: PUT, auth: true, @@ -87,7 +86,7 @@ module.exports = { }, }, }, - [SERVICETEMPLATE_DELETE]: { + [SERVICE_TEMPLATE_DELETE]: { path: `${basepath}/:id`, httpMethod: DELETE, auth: true, diff --git a/src/fireedge/src/server/routes/api/oneprovision/basepath.js b/src/fireedge/src/server/routes/api/oneprovision/basepath.js deleted file mode 100644 index a856276608..0000000000 --- a/src/fireedge/src/server/routes/api/oneprovision/basepath.js +++ /dev/null @@ -1,25 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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. * - * ------------------------------------------------------------------------- */ - -const PROVIDER = 'provider' -const PROVISION = 'provision' -const PROVISION_TEMPLATE = 'provision-template' - -module.exports = { - PROVIDER, - PROVISION, - PROVISION_TEMPLATE, -} diff --git a/src/fireedge/src/server/routes/api/oneprovision/index.js b/src/fireedge/src/server/routes/api/oneprovision/index.js index dd531ff0dc..cbadd9dab2 100644 --- a/src/fireedge/src/server/routes/api/oneprovision/index.js +++ b/src/fireedge/src/server/routes/api/oneprovision/index.js @@ -25,7 +25,6 @@ const { deleteResource, deleteProvision, hostCommand, - hostCommandSSH, hostAdd, ipAdd, createProvision, @@ -61,33 +60,17 @@ const { } = require('server/routes/api/oneprovision/provider/functions') const { - PROVISION_CLUSTER_RESOURCE, - PROVISION_DATASTORE_RESOURCE, - PROVISION_HOST_RESOURCE, - PROVISION_IMAGE_RESOURCE, - PROVISION_NETWORK_RESOURCE, - PROVISION_TEMPLATE_RESOURCE, - PROVISION_VNTEMPLATE_RESOURCE, PROVISION_LOGS, PROVISION_DEFAULTS, PROVISION_LIST, PROVISION_VALIDATE, - PROVISION_HOST_POWEROFF, - PROVISION_HOST_REBOOT, - PROVISION_HOST_RESUME, PROVISION_CREATE, - PROVISION_HOST_SSH, - PROVISION_DATASTORE, - PROVISION_FLOWTEMPLATE, - PROVISION_DELETE_HOST_RESOURCE, - PROVISION_DELETE_IMAGE_RESOURCE, - PROVISION_DELETE_NETWORK_RESOURCE, - PROVISION_DELETE_VNTEMPLATE_RESOURCE, - PROVISION_DELETE_TEMPLATE_RESOURCE, - PROVISION_DELETE_CLUSTER_RESOURCE, - PROVISION_DELETE_PROVISION, - PROVISION_UPDATE_CONFIGURE, - PROVISION_UPDATE_HOST, + PROVISION_DELETE, + PROVISION_CONFIGURE, + PROVISION_GET_RESOURCE, + PROVISION_DELETE_RESOURCE, + PROVISION_HOST_ACTION, + PROVISION_HOST_CONFIGURE, PROVISION_ADD_HOST, PROVISION_ADD_IP, } = ActionsProvision @@ -112,32 +95,12 @@ const { module.exports = [ // Provision { - ...CommandsProvision[PROVISION_CLUSTER_RESOURCE], + ...CommandsProvision[PROVISION_GET_RESOURCE], action: getListResourceProvision, }, { - ...CommandsProvision[PROVISION_DATASTORE_RESOURCE], - action: getListResourceProvision, - }, - { - ...CommandsProvision[PROVISION_HOST_RESOURCE], - action: getListResourceProvision, - }, - { - ...CommandsProvision[PROVISION_IMAGE_RESOURCE], - action: getListResourceProvision, - }, - { - ...CommandsProvision[PROVISION_NETWORK_RESOURCE], - action: getListResourceProvision, - }, - { - ...CommandsProvision[PROVISION_TEMPLATE_RESOURCE], - action: getListResourceProvision, - }, - { - ...CommandsProvision[PROVISION_VNTEMPLATE_RESOURCE], - action: getListResourceProvision, + ...CommandsProvision[PROVISION_DELETE_RESOURCE], + action: deleteResource, }, { ...CommandsProvision[PROVISION_LOGS], @@ -156,15 +119,7 @@ module.exports = [ action: validate, }, { - ...CommandsProvision[PROVISION_HOST_POWEROFF], - action: hostCommand, - }, - { - ...CommandsProvision[PROVISION_HOST_REBOOT], - action: hostCommand, - }, - { - ...CommandsProvision[PROVISION_HOST_RESUME], + ...CommandsProvision[PROVISION_HOST_ACTION], action: hostCommand, }, { @@ -172,51 +127,15 @@ module.exports = [ action: createProvision, }, { - ...CommandsProvision[PROVISION_HOST_SSH], - action: hostCommandSSH, - }, - { - ...CommandsProvision[PROVISION_DATASTORE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_FLOWTEMPLATE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_DELETE_HOST_RESOURCE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_DELETE_IMAGE_RESOURCE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_DELETE_NETWORK_RESOURCE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_DELETE_VNTEMPLATE_RESOURCE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_DELETE_TEMPLATE_RESOURCE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_DELETE_CLUSTER_RESOURCE], - action: deleteResource, - }, - { - ...CommandsProvision[PROVISION_DELETE_PROVISION], - action: deleteProvision, - }, - { - ...CommandsProvision[PROVISION_UPDATE_CONFIGURE], + ...CommandsProvision[PROVISION_CONFIGURE], action: configureProvision, }, { - ...CommandsProvision[PROVISION_UPDATE_HOST], + ...CommandsProvision[PROVISION_DELETE], + action: deleteProvision, + }, + { + ...CommandsProvision[PROVISION_HOST_CONFIGURE], action: configureHost, }, { @@ -227,8 +146,8 @@ module.exports = [ ...CommandsProvision[PROVISION_ADD_IP], action: ipAdd, }, - // Template + // Template { ...CommandsTemplate[PROVISIONTEMPLATE_SHOW], action: getListProvisionTemplates, diff --git a/src/fireedge/src/server/routes/api/oneprovision/provider/functions.js b/src/fireedge/src/server/routes/api/oneprovision/provider/functions.js index d1b24b625a..6e47b6585a 100644 --- a/src/fireedge/src/server/routes/api/oneprovision/provider/functions.js +++ b/src/fireedge/src/server/routes/api/oneprovision/provider/functions.js @@ -270,11 +270,12 @@ const createProviders = ( ) => { const { user, password } = userData const rtn = httpInternalError - if (params && params.resource && user && password) { + if (params && params.data && user && password) { const authCommand = ['--user', user, '--password', password] const endpoint = getEndpoint() - const resource = parsePostData(params.resource) + const resource = parsePostData(params.data) const content = createYMLContent(resource) + if (content) { const file = createTemporalFile( `${global.paths.CPI}/${defaultFolderTmpProvision}`, @@ -331,10 +332,10 @@ const updateProviders = ( ) => { const { user, password } = userData const rtn = httpInternalError - if (params && params.resource && params.id && user && password) { + if (params && params.data && params.id && user && password) { const authCommand = ['--user', user, '--password', password] const endpoint = getEndpoint() - const resource = parsePostData(params.resource) + const resource = parsePostData(params.data) const file = createTemporalFile( `${global.paths.CPI}/${defaultFolderTmpProvision}`, 'json', diff --git a/src/fireedge/src/server/routes/api/oneprovision/provider/routes.js b/src/fireedge/src/server/routes/api/oneprovision/provider/routes.js index b5d0160cd0..ac3817fc4b 100644 --- a/src/fireedge/src/server/routes/api/oneprovision/provider/routes.js +++ b/src/fireedge/src/server/routes/api/oneprovision/provider/routes.js @@ -17,12 +17,11 @@ const { from: fromData, httpMethod, -} = require('server/utils/constants/defaults') -const { PROVIDER } = require('server/routes/api/oneprovision/basepath') +} = require('../../../../utils/constants/defaults') const { GET, POST, PUT, DELETE } = httpMethod -const basepath = `/${PROVIDER}` const { resource, postBody } = fromData +const basepath = '/provider' const PROVIDER_CONNECTION = 'provider.connection' const PROVIDER_CONFIG = 'provider.config' @@ -73,9 +72,8 @@ module.exports = { httpMethod: POST, auth: true, params: { - resource: { + data: { from: postBody, - all: true, }, }, }, @@ -84,9 +82,8 @@ module.exports = { httpMethod: PUT, auth: true, params: { - resource: { + data: { from: postBody, - all: true, }, id: { from: resource }, }, diff --git a/src/fireedge/src/server/routes/api/oneprovision/provision/functions.js b/src/fireedge/src/server/routes/api/oneprovision/provision/functions.js index 4a56e7ad3c..5f0291b9ea 100644 --- a/src/fireedge/src/server/routes/api/oneprovision/provision/functions.js +++ b/src/fireedge/src/server/routes/api/oneprovision/provision/functions.js @@ -790,67 +790,6 @@ const hostCommand = ( next() } -/** - * SSH command of host into provision. - * - * @param {object} res - http response - * @param {Function} next - express stepper - * @param {object} params - params of http request - * @param {string} params.action - provision action - * @param {number} params.id - provision id - * @param {string} params.command - provision command - * @param {object} userData - user of http request - * @param {string} userData.user - username - * @param {string} userData.password - user password - */ -const hostCommandSSH = ( - res = {}, - next = defaultEmptyFunction, - params = {}, - userData = {} -) => { - const { user, password } = userData - const { action, id, command } = params - let rtn = httpInternalError - if ( - action && - Number.isInteger(parseInt(id, 10)) && - command && - user && - password - ) { - const endpoint = getEndpoint() - const authCommand = ['--user', user, '--password', password] - const paramsCommand = [ - 'host', - `${action}`.toLowerCase(), - `${id}`.toLowerCase(), - `${command}`.toLowerCase(), - ...authCommand, - ...endpoint, - ] - const executedCommand = executeCommand( - defaultCommandProvision, - paramsCommand, - getSpecificConfig('oneprovision_prepend_command') - ) - try { - const response = executedCommand.success ? ok : internalServerError - res.locals.httpCode = httpResponse( - response, - executedCommand.data ? JSON.parse(executedCommand.data) : params.id - ) - next() - - return - } catch (error) { - rtn = httpResponse(internalServerError, '', executedCommand.data) - } - } - res.locals.httpCode = rtn - next() -} - /** * Create a provision. * @@ -876,11 +815,12 @@ const createProvision = ( const relFileYML = `${relFile}.${ext}` const relFileLOCK = `${relFile}.lock` const { user, password, id } = userData - const { resource } = params + const { data } = params const rtn = httpInternalError - if (resource && user && password) { + if (data && user && password) { const optionalCommand = addOptionalCreateCommand() - const content = createYMLContent(parsePostData(params.resource)) + const content = createYMLContent(parsePostData(data)) + if (content) { const command = 'create' const authCommand = ['--user', user, '--password', password] @@ -1053,7 +993,7 @@ const createProvision = ( * @param {object} res - http response * @param {Function} next - express stepper * @param {object} params - params of http request - * @param {number} params.id - proivision id + * @param {number} params.id - provision id * @param {object} userData - user of http request * @param {string} userData.user - username * @param {string} userData.password - user password @@ -1489,7 +1429,6 @@ const provisionFunctionsApi = { deleteResource, deleteProvision, hostCommand, - hostCommandSSH, createProvision, configureProvision, configureHost, diff --git a/src/fireedge/src/server/routes/api/oneprovision/provision/routes.js b/src/fireedge/src/server/routes/api/oneprovision/provision/routes.js index f913ddb35b..0c1dc0e80e 100644 --- a/src/fireedge/src/server/routes/api/oneprovision/provision/routes.js +++ b/src/fireedge/src/server/routes/api/oneprovision/provision/routes.js @@ -17,71 +17,40 @@ const { httpMethod, from: fromData, -} = require('server/utils/constants/defaults') -const { PROVISION } = require('server/routes/api/oneprovision/basepath') +} = require('../../../../utils/constants/defaults') const { GET, POST, DELETE, PUT } = httpMethod -const basepath = `/${PROVISION}` const { resource, postBody } = fromData +const basepath = '/provision' -const PROVISION_CLUSTER_RESOURCE = 'provision.clusterresource' -const PROVISION_DATASTORE_RESOURCE = 'provision.datastoreresource' -const PROVISION_HOST_RESOURCE = 'provision.hostresource' -const PROVISION_IMAGE_RESOURCE = 'provision.imageresource' -const PROVISION_NETWORK_RESOURCE = 'provision.networkresource' -const PROVISION_TEMPLATE_RESOURCE = 'provision.templateresource' -const PROVISION_VNTEMPLATE_RESOURCE = 'provision.vntemplateresource' const PROVISION_LOGS = 'provision.logs' -const PROVISION_DEFAULTS = 'provision.defauls' +const PROVISION_DEFAULTS = 'provision.defaults' const PROVISION_LIST = 'provision.list' const PROVISION_VALIDATE = 'provision.validate' -const PROVISION_HOST_POWEROFF = 'provision.hostpoweroff' -const PROVISION_HOST_REBOOT = 'provision.hostreboot' -const PROVISION_HOST_RESUME = 'provision.hostresume' const PROVISION_CREATE = 'provision.create' -const PROVISION_HOST_SSH = 'provision.hostssh' -const PROVISION_DATASTORE = 'provision.datastore' -const PROVISION_FLOWTEMPLATE = 'provision.flowtemplate' -const PROVISION_DELETE_HOST_RESOURCE = 'provision.deletehostresource' -const PROVISION_DELETE_IMAGE_RESOURCE = 'provision.deleteimageresource' -const PROVISION_DELETE_NETWORK_RESOURCE = 'provision.deletenetworkresource' -const PROVISION_DELETE_VNTEMPLATE_RESOURCE = 'provision.deletevntemplate' -const PROVISION_DELETE_TEMPLATE_RESOURCE = 'provision.deletetemplateresource' -const PROVISION_DELETE_CLUSTER_RESOURCE = 'provision.deleteclusterresource' -const PROVISION_DELETE_PROVISION = 'provision.deleteprovision' -const PROVISION_UPDATE_CONFIGURE = 'provision.updateconfigure' -const PROVISION_UPDATE_HOST = 'provision.updatehost' -const PROVISION_ADD_HOST = 'provison.addhost' -const PROVISION_ADD_IP = 'provision.addip' +const PROVISION_DELETE = 'provision.delete' +const PROVISION_CONFIGURE = 'provision.configure' +// cluster, datastore, host, image, network, template, vntemplate, flowtemplate +const PROVISION_GET_RESOURCE = 'provision.get_resource' +const PROVISION_DELETE_RESOURCE = 'provision.delete_resource' +// actions: poweroff, reboot, resume, update, configure, ssh +const PROVISION_HOST_ACTION = 'provision.host_action' +const PROVISION_HOST_CONFIGURE = 'provision.host_configure' +const PROVISION_ADD_HOST = 'provison.add_host' +const PROVISION_ADD_IP = 'provision.add_ip' const Actions = { - PROVISION_CLUSTER_RESOURCE, - PROVISION_DATASTORE_RESOURCE, - PROVISION_HOST_RESOURCE, - PROVISION_IMAGE_RESOURCE, - PROVISION_NETWORK_RESOURCE, - PROVISION_TEMPLATE_RESOURCE, - PROVISION_VNTEMPLATE_RESOURCE, PROVISION_LOGS, PROVISION_DEFAULTS, PROVISION_LIST, PROVISION_VALIDATE, - PROVISION_HOST_POWEROFF, - PROVISION_HOST_REBOOT, - PROVISION_HOST_RESUME, PROVISION_CREATE, - PROVISION_HOST_SSH, - PROVISION_DATASTORE, - PROVISION_FLOWTEMPLATE, - PROVISION_DELETE_HOST_RESOURCE, - PROVISION_DELETE_IMAGE_RESOURCE, - PROVISION_DELETE_NETWORK_RESOURCE, - PROVISION_DELETE_VNTEMPLATE_RESOURCE, - PROVISION_DELETE_TEMPLATE_RESOURCE, - PROVISION_DELETE_CLUSTER_RESOURCE, - PROVISION_DELETE_PROVISION, - PROVISION_UPDATE_CONFIGURE, - PROVISION_UPDATE_HOST, + PROVISION_DELETE, + PROVISION_CONFIGURE, + PROVISION_GET_RESOURCE, + PROVISION_DELETE_RESOURCE, + PROVISION_HOST_ACTION, + PROVISION_HOST_CONFIGURE, PROVISION_ADD_HOST, PROVISION_ADD_IP, } @@ -89,76 +58,6 @@ const Actions = { module.exports = { Actions, Commands: { - [PROVISION_CLUSTER_RESOURCE]: { - path: `${basepath}/cluster/:resource`, - httpMethod: GET, - auth: true, - params: { - resource: { - from: resource, - }, - }, - }, - [PROVISION_DATASTORE_RESOURCE]: { - path: `${basepath}/datastore/:resource`, - httpMethod: GET, - auth: true, - params: { - resource: { - from: resource, - }, - }, - }, - [PROVISION_HOST_RESOURCE]: { - path: `${basepath}/host/:resource`, - httpMethod: GET, - auth: true, - params: { - resource: { - from: resource, - }, - }, - }, - [PROVISION_IMAGE_RESOURCE]: { - path: `${basepath}/image/:resource`, - httpMethod: GET, - auth: true, - params: { - resource: { - from: resource, - }, - }, - }, - [PROVISION_NETWORK_RESOURCE]: { - path: `${basepath}/network/:resource`, - httpMethod: GET, - auth: true, - params: { - resource: { - from: resource, - }, - }, - }, - [PROVISION_TEMPLATE_RESOURCE]: { - path: `${basepath}/template/:resource`, - httpMethod: GET, - auth: true, - params: { - resource: { - from: resource, - }, - }, - }, - [PROVISION_VNTEMPLATE_RESOURCE]: { - path: `${basepath}/vntemplate/:resource`, - httpMethod: GET, - auth: true, - params: { - resource: { - from: resource, - }, - }, - }, [PROVISION_LOGS]: { path: `${basepath}/log/:id`, httpMethod: GET, @@ -194,177 +93,17 @@ module.exports = { }, }, }, - [PROVISION_HOST_POWEROFF]: { - path: `${basepath}/host/poweroff/:action/:id`, - httpMethod: POST, - auth: true, - params: { - action: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_HOST_REBOOT]: { - path: `${basepath}/host/reboot/:action/:id`, - httpMethod: POST, - auth: true, - params: { - action: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_HOST_RESUME]: { - path: `${basepath}/host/resume/:action/:id`, - httpMethod: POST, - auth: true, - params: { - action: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, [PROVISION_CREATE]: { path: `${basepath}`, httpMethod: POST, auth: true, params: { - resource: { - from: postBody, - all: true, - }, - }, - }, - [PROVISION_HOST_SSH]: { - path: `${basepath}/host/ssh/:action/:id/:command`, - httpMethod: DELETE, - auth: true, - params: { - action: { - from: resource, - }, - id: { - from: resource, - }, - command: { + data: { from: postBody, }, }, }, - [PROVISION_DATASTORE]: { - path: `${basepath}/datastore/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_FLOWTEMPLATE]: { - path: `${basepath}/flowtemplate/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_DELETE_HOST_RESOURCE]: { - path: `${basepath}/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_DELETE_IMAGE_RESOURCE]: { - path: `${basepath}/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_DELETE_NETWORK_RESOURCE]: { - path: `${basepath}/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_DELETE_VNTEMPLATE_RESOURCE]: { - path: `${basepath}/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_DELETE_TEMPLATE_RESOURCE]: { - path: `${basepath}/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_DELETE_CLUSTER_RESOURCE]: { - path: `${basepath}/:resource/:id`, - httpMethod: DELETE, - auth: true, - params: { - resource: { - from: resource, - }, - id: { - from: resource, - }, - }, - }, - [PROVISION_DELETE_PROVISION]: { + [PROVISION_DELETE]: { path: `${basepath}/:id`, httpMethod: DELETE, auth: true, @@ -380,7 +119,7 @@ module.exports = { }, }, }, - [PROVISION_UPDATE_CONFIGURE]: { + [PROVISION_CONFIGURE]: { path: `${basepath}/configure/:id`, httpMethod: PUT, auth: true, @@ -390,7 +129,43 @@ module.exports = { }, }, }, - [PROVISION_UPDATE_HOST]: { + [PROVISION_GET_RESOURCE]: { + path: `${basepath}/resource/:resource`, + httpMethod: GET, + auth: true, + params: { + resource: { + from: resource, + }, + }, + }, + [PROVISION_DELETE_RESOURCE]: { + path: `${basepath}/resource/:resource/:id`, + httpMethod: DELETE, + auth: true, + params: { + resource: { + from: resource, + }, + id: { + from: resource, + }, + }, + }, + [PROVISION_HOST_ACTION]: { + path: `${basepath}/host/:action/:id`, + httpMethod: POST, + auth: true, + params: { + action: { + from: resource, + }, + id: { + from: resource, + }, + }, + }, + [PROVISION_HOST_CONFIGURE]: { path: `${basepath}/host/:id`, httpMethod: PUT, auth: true, diff --git a/src/fireedge/src/server/routes/api/oneprovision/template/routes.js b/src/fireedge/src/server/routes/api/oneprovision/template/routes.js index cbe4bcb7e2..7f37eb4983 100644 --- a/src/fireedge/src/server/routes/api/oneprovision/template/routes.js +++ b/src/fireedge/src/server/routes/api/oneprovision/template/routes.js @@ -16,11 +16,8 @@ const { from: fromData } = require('server/utils/constants/defaults') const { httpMethod } = require('server/utils/constants/defaults') -const { - PROVISION_TEMPLATE, -} = require('server/routes/api/oneprovision/basepath') -const basepath = `/${PROVISION_TEMPLATE}` +const basepath = '/provision-template' const { GET, POST, PUT, DELETE } = httpMethod const { resource, postBody } = fromData diff --git a/src/fireedge/src/server/routes/api/sunstone/basepath.js b/src/fireedge/src/server/routes/api/sunstone/basepath.js deleted file mode 100644 index 6681f23fe1..0000000000 --- a/src/fireedge/src/server/routes/api/sunstone/basepath.js +++ /dev/null @@ -1,17 +0,0 @@ -/* ------------------------------------------------------------------------- * - * Copyright 2002-2021, OpenNebula Project, OpenNebula Systems * - * * - * Licensed 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. * - * ------------------------------------------------------------------------- */ - -module.exports = 'sunstone' diff --git a/src/fireedge/src/server/routes/api/sunstone/routes.js b/src/fireedge/src/server/routes/api/sunstone/routes.js index 7b427993d0..04ae62adf0 100644 --- a/src/fireedge/src/server/routes/api/sunstone/routes.js +++ b/src/fireedge/src/server/routes/api/sunstone/routes.js @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * * limitations under the License. * * ------------------------------------------------------------------------- */ - -const { httpMethod } = require('server/utils/constants/defaults') -const SUNSTONE = require('server/routes/api/sunstone/basepath') +const { httpMethod } = require('../../../utils/constants/defaults') const { GET } = httpMethod -const basepath = `/${SUNSTONE}` + +const basepath = '/sunstone' const SUNSTONE_VIEWS = 'sunstone.views' const SUNSTONE_CONFIG = 'sunstone.config' diff --git a/src/fireedge/src/server/utils/constants/commands/market.js b/src/fireedge/src/server/utils/constants/commands/market.js index 8b69e1abab..3232a720f2 100644 --- a/src/fireedge/src/server/utils/constants/commands/market.js +++ b/src/fireedge/src/server/utils/constants/commands/market.js @@ -25,6 +25,7 @@ const MARKET_UPDATE = 'market.update' const MARKET_CHMOD = 'market.chmod' const MARKET_CHOWN = 'market.chown' const MARKET_RENAME = 'market.rename' +const MARKET_ENABLE = 'market.enable' const MARKET_INFO = 'market.info' const MARKET_POOL_INFO = 'marketpool.info' @@ -35,6 +36,7 @@ const Actions = { MARKET_CHMOD, MARKET_CHOWN, MARKET_RENAME, + MARKET_ENABLE, MARKET_INFO, MARKET_POOL_INFO, } @@ -158,6 +160,20 @@ module.exports = { }, }, }, + [MARKET_ENABLE]: { + // inspected + httpMethod: PUT, + params: { + id: { + from: resource, + default: 0, + }, + enable: { + from: postBody, + default: true, + }, + }, + }, [MARKET_INFO]: { // inspected httpMethod: GET, diff --git a/src/fireedge/src/server/utils/constants/commands/user.js b/src/fireedge/src/server/utils/constants/commands/user.js index 0a34f04dbb..f844b378a3 100644 --- a/src/fireedge/src/server/utils/constants/commands/user.js +++ b/src/fireedge/src/server/utils/constants/commands/user.js @@ -29,6 +29,7 @@ const USER_QUOTA = 'user.quota' const USER_CHGRP = 'user.chgrp' const USER_ADDGROUP = 'user.addgroup' const USER_DELGROUP = 'user.delgroup' +const USER_ENABLE = 'user.enable' const USER_INFO = 'user.info' const USER_POOL_INFO = 'userpool.info' const USER_QUOTA_INFO = 'userquota.info' @@ -214,6 +215,20 @@ module.exports = { }, }, }, + [USER_ENABLE]: { + // inspected + httpMethod: PUT, + params: { + id: { + from: resource, + default: 0, + }, + enable: { + from: postBody, + default: true, + }, + }, + }, [USER_INFO]: { // inspected httpMethod: GET, diff --git a/src/fireedge/src/server/utils/constants/commands/vm.js b/src/fireedge/src/server/utils/constants/commands/vm.js index 34d0b6e674..7f2f767593 100644 --- a/src/fireedge/src/server/utils/constants/commands/vm.js +++ b/src/fireedge/src/server/utils/constants/commands/vm.js @@ -612,7 +612,7 @@ module.exports = { from: resource, default: 0, }, - id_sched: { + schedId: { from: postBody, default: 0, }, @@ -629,7 +629,7 @@ module.exports = { from: resource, default: 0, }, - id_sched: { + schedId: { from: postBody, default: 0, }, @@ -653,7 +653,7 @@ module.exports = { }, state: { from: query, - default: -2, + default: -1, }, filterByKey: { from: query, @@ -679,7 +679,7 @@ module.exports = { }, state: { from: query, - default: -2, + default: -1, }, filterBykey: { from: query, @@ -695,6 +695,10 @@ module.exports = { from: query, default: -2, }, + seconds: { + from: query, + default: -1, + }, }, }, [VM_POOL_ACCOUNTING]: {