diff --git a/package-lock.json b/package-lock.json index b2881422fb..53e8260b1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "react-hotkeys-hook": "^4.4.4", "react-i18next": "^15.0.1", "react-icons": "^5.2.1", + "react-js-cron": "^5.0.1", "react-redux": "^7.2.9", "react-router-dom": "^6.26.1", "react-select": "^5.8.0", @@ -83,6 +84,115 @@ "node": ">=6.0.0" } }, + "node_modules/@ant-design/colors": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.1.0.tgz", + "integrity": "sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==", + "peer": true, + "dependencies": { + "@ctrl/tinycolor": "^3.6.1" + } + }, + "node_modules/@ant-design/cssinjs": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.22.0.tgz", + "integrity": "sha512-W9XSFeRPR0mAN3OuxfuS/xhENCYKf+8s+QyNNER0FSWoK9OpISTag6CCweg6lq0hASQ/2Vcza0Z8/kGivCP0Ng==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.3.4" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/cssinjs-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.1.tgz", + "integrity": "sha512-2HAiyGGGnM0es40SxdszeQAU5iWp41wBIInq+ONTCKjlSKOrzQfnw4JDtB8IBmqE6tQaEKwmzTP2LGdt5DSwYQ==", + "peer": true, + "dependencies": { + "@ant-design/cssinjs": "^1.21.0", + "@babel/runtime": "^7.23.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@ant-design/cssinjs/node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "peer": true + }, + "node_modules/@ant-design/cssinjs/node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==", + "peer": true + }, + "node_modules/@ant-design/fast-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", + "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.7" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@ant-design/icons": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.5.1.tgz", + "integrity": "sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==", + "peer": true, + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.4.0", + "@babel/runtime": "^7.24.8", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", + "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==", + "peer": true + }, + "node_modules/@ant-design/react-slick": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", + "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", @@ -2188,9 +2298,9 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", - "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -2252,6 +2362,15 @@ "node": ">=6.9.0" } }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "peer": true, + "engines": { + "node": ">=10" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.11.0", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", @@ -2306,6 +2425,12 @@ "stylis": "4.2.0" } }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "peer": true + }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", @@ -3443,6 +3568,155 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rc-component/async-validator": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", + "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.4" + }, + "engines": { + "node": ">=14.x" + } + }, + "node_modules/@rc-component/color-picker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz", + "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==", + "peer": true, + "dependencies": { + "@ant-design/fast-color": "^2.0.6", + "@babel/runtime": "^7.23.6", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/context": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/mini-decimal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@rc-component/mutate-observer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", + "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/qrcode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.0.tgz", + "integrity": "sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.7", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/tour": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz", + "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/trigger": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.2.5.tgz", + "integrity": "sha512-F1EJ4KjFpGAHAjuKvOyZB/6IZDkVx0bHl0M4fQM5wXcmm7lgTgVSSnR3bXwdmS6jOJGHOqfDxIJW3WUvwMIXhQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.38.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/@redux-devtools/extension": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@redux-devtools/extension/-/extension-3.3.0.tgz", @@ -3516,9 +3790,9 @@ "dev": true }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz", - "integrity": "sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", "cpu": [ "arm" ], @@ -3529,9 +3803,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz", - "integrity": "sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", "cpu": [ "arm64" ], @@ -3542,9 +3816,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz", - "integrity": "sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", "cpu": [ "arm64" ], @@ -3555,9 +3829,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz", - "integrity": "sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", "cpu": [ "x64" ], @@ -3567,10 +3841,36 @@ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz", - "integrity": "sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", "cpu": [ "arm" ], @@ -3581,9 +3881,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz", - "integrity": "sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", "cpu": [ "arm" ], @@ -3594,9 +3894,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz", - "integrity": "sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", "cpu": [ "arm64" ], @@ -3607,9 +3907,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz", - "integrity": "sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", "cpu": [ "arm64" ], @@ -3620,9 +3920,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz", - "integrity": "sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", "cpu": [ "ppc64" ], @@ -3633,9 +3933,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz", - "integrity": "sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", "cpu": [ "riscv64" ], @@ -3646,9 +3946,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz", - "integrity": "sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", "cpu": [ "s390x" ], @@ -3659,9 +3959,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz", - "integrity": "sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", "cpu": [ "x64" ], @@ -3672,9 +3972,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz", - "integrity": "sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", "cpu": [ "x64" ], @@ -3685,9 +3985,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz", - "integrity": "sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", "cpu": [ "arm64" ], @@ -3698,9 +3998,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz", - "integrity": "sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", "cpu": [ "ia32" ], @@ -3711,9 +4011,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz", - "integrity": "sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", "cpu": [ "x64" ], @@ -4191,9 +4491,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true }, "node_modules/@types/history": { @@ -5230,6 +5530,71 @@ "node": ">=4" } }, + "node_modules/antd": { + "version": "5.22.2", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.22.2.tgz", + "integrity": "sha512-vihhiJbm9VG3d6boUeD1q2MXMax+qBrXhgqCEC+45v8iGUF6m4Ct+lFiCW4oWaN3EABOsbVA6Svy3Rj/QkQFKw==", + "peer": true, + "dependencies": { + "@ant-design/colors": "^7.1.0", + "@ant-design/cssinjs": "^1.21.1", + "@ant-design/cssinjs-utils": "^1.1.1", + "@ant-design/icons": "^5.5.1", + "@ant-design/react-slick": "~1.1.2", + "@babel/runtime": "^7.25.7", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~2.0.1", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/qrcode": "~1.0.0", + "@rc-component/tour": "~1.15.1", + "@rc-component/trigger": "^2.2.5", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.11", + "rc-cascader": "~3.30.0", + "rc-checkbox": "~3.3.0", + "rc-collapse": "~3.9.0", + "rc-dialog": "~9.6.0", + "rc-drawer": "~7.2.0", + "rc-dropdown": "~4.2.0", + "rc-field-form": "~2.5.1", + "rc-image": "~7.11.0", + "rc-input": "~1.6.3", + "rc-input-number": "~9.3.0", + "rc-mentions": "~2.17.0", + "rc-menu": "~9.16.0", + "rc-motion": "^2.9.3", + "rc-notification": "~5.6.2", + "rc-pagination": "~4.3.0", + "rc-picker": "~4.8.1", + "rc-progress": "~4.0.0", + "rc-rate": "~2.13.0", + "rc-resize-observer": "^1.4.0", + "rc-segmented": "~2.5.0", + "rc-select": "~14.16.3", + "rc-slider": "~11.1.7", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.48.1", + "rc-tabs": "~15.4.0", + "rc-textarea": "~1.8.2", + "rc-tooltip": "~6.2.1", + "rc-tree": "~5.10.1", + "rc-tree-select": "~5.24.4", + "rc-upload": "~4.8.1", + "rc-util": "^5.43.0", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ant-design" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -5898,6 +6263,12 @@ "node": ">= 0.8" } }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", + "integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==", + "peer": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -5917,6 +6288,15 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "peer": true, + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, "node_modules/core-js-compat": { "version": "3.37.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", @@ -5956,9 +6336,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -6070,6 +6450,12 @@ "url": "https://github.com/sponsors/kossnocorp" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "peer": true + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -8089,15 +8475,15 @@ } }, "node_modules/http-proxy-middleware": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.1.tgz", - "integrity": "sha512-5TnsBzyqlWRdT525r198AR1kGc5zIIlZNBZdmP7BUILe3yI8gDgNMbxyQpW+tMBPZQln/1T6p6mCVb0oCVKaiw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", + "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", "dependencies": { "@types/http-proxy": "^1.17.15", "debug": "^4.3.6", "http-proxy": "^1.18.1", "is-glob": "^4.0.3", - "is-plain-obj": "^3.0.0", + "is-plain-object": "^5.0.0", "micromatch": "^4.0.8" }, "engines": { @@ -8488,15 +8874,12 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/is-regex": { @@ -8729,6 +9112,15 @@ "dev": true, "license": "MIT" }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "peer": true, + "dependencies": { + "string-convert": "^0.2.0" + } + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -9400,10 +9792,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "license": "ISC" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -9529,6 +9920,611 @@ "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" }, + "node_modules/rc-cascader": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.30.0.tgz", + "integrity": "sha512-rrzSbk1Bdqbu+pDwiLCLHu72+lwX9BZ28+JKzoi0DWZ4N29QYFeip8Gctl33QVd2Xg3Rf14D3yAOG76ElJw16w==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.7", + "classnames": "^2.3.1", + "rc-select": "~14.16.2", + "rc-tree": "~5.10.1", + "rc-util": "^5.43.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-checkbox": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", + "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-collapse": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.9.0.tgz", + "integrity": "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dialog": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz", + "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-drawer": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", + "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dropdown": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz", + "integrity": "sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" + } + }, + "node_modules/rc-field-form": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.5.1.tgz", + "integrity": "sha512-33hunXwynQJyeae7LS3hMGTXNeRBjiPyPYgB0824EbmLHiXC1EBGyUwRh6xjLRy9c+en5WARYN0gJz5+JAqwig==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/async-validator": "^5.0.3", + "rc-util": "^5.32.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-image": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.0.tgz", + "integrity": "sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.6.0", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-input": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.3.tgz", + "integrity": "sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-input-number": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.3.0.tgz", + "integrity": "sha512-JQ363ywqRyxwgVxpg2z2kja3CehTpYdqR7emJ/6yJjRdbvo+RvfE83fcpBCIJRq3zLp8SakmEXq60qzWyZ7Usw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.6.0", + "rc-util": "^5.40.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-mentions": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.17.0.tgz", + "integrity": "sha512-sfHy+qLvc+p8jx8GUsujZWXDOIlIimp6YQz7N5ONQ6bHsa2kyG+BLa5k2wuxgebBbH97is33wxiyq5UkiXRpHA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-input": "~1.6.0", + "rc-menu": "~9.16.0", + "rc-textarea": "~1.8.0", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-menu": { + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.16.0.tgz", + "integrity": "sha512-vAL0yqPkmXWk3+YKRkmIR8TYj3RVdEt3ptG2jCJXWNAvQbT0VJJdRyHZ7kG/l1JsZlB+VJq/VcYOo69VR4oD+w==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.0.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-motion": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.3.tgz", + "integrity": "sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.43.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-notification": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.2.tgz", + "integrity": "sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-overflow": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz", + "integrity": "sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-pagination": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.3.0.tgz", + "integrity": "sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-picker": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.8.2.tgz", + "integrity": "sha512-I6Nn4ngkRskSD//rsXDvjlEQ8CzX9kPQrUIb7+qTY49erJaa3/oKJWmi6JIxo/A7gy59phNmPTdhKosAa/NrQQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.24.7", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.1", + "rc-overflow": "^1.3.2", + "rc-resize-observer": "^1.4.0", + "rc-util": "^5.43.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "date-fns": ">= 2.x", + "dayjs": ">= 1.x", + "luxon": ">= 3.x", + "moment": ">= 2.x", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + }, + "peerDependenciesMeta": { + "date-fns": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + } + } + }, + "node_modules/rc-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", + "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-rate": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.0.tgz", + "integrity": "sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-resize-observer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz", + "integrity": "sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.38.0", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-segmented": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz", + "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-select": { + "version": "14.16.3", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.16.3.tgz", + "integrity": "sha512-51+j6s3fJJJXB7E+B6W1hM4Tjzv1B/Decooz9ilgegDBt3ZAth1b/xMwYCTrT5BbG2e53XACQsyDib2+3Ro1fg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.1.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-slider": { + "version": "11.1.7", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.7.tgz", + "integrity": "sha512-ytYbZei81TX7otdC0QvoYD72XSlxvTihNth5OeZ6PMXyEDq/vHdWFulQmfDGyXK1NwKwSlKgpvINOa88uT5g2A==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-steps": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", + "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-switch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", + "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-table": { + "version": "7.48.1", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.48.1.tgz", + "integrity": "sha512-Z4mDKjWg+xz/Ezdw6ivWcbqRpaJ0QfCORRoRrlrw65KSGZLK8OcTdacH22/fyGb8L4It/0/9qcMm8VrVAk/WBw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.41.0", + "rc-virtual-list": "^3.14.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tabs": { + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.4.0.tgz", + "integrity": "sha512-llKuyiAVqmXm2z7OrmhX5cNb2ueZaL8ZyA2P4R+6/72NYYcbEgOXibwHiQCFY2RiN3swXl53SIABi2CumUS02g==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.2.0", + "rc-menu": "~9.16.0", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-textarea": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz", + "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.6.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tooltip": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz", + "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tree": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.10.1.tgz", + "integrity": "sha512-FPXb3tT/u39mgjr6JNlHaUTYfHkVGW56XaGDahDpEFLGsnPxGcVLNTjcqoQb/GNbSCycl7tD7EvIymwOTP0+Yw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + }, + "engines": { + "node": ">=10.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-tree-select": { + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.24.5.tgz", + "integrity": "sha512-PnyR8LZJWaiEFw0SHRqo4MNQWyyZsyMs8eNmo68uXZWjxc7QqeWcjPPoONN0rc90c3HZqGF9z+Roz+GLzY5GXA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.7", + "classnames": "2.x", + "rc-select": "~14.16.2", + "rc-tree": "~5.10.1", + "rc-util": "^5.43.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-upload": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz", + "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util": { + "version": "5.43.0", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.43.0.tgz", + "integrity": "sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "react-is": "^18.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-virtual-list": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.15.0.tgz", + "integrity": "sha512-dF2YQztqrU3ijAeWOqscTshCEr7vpimzSqAVjO1AyAmaqcHulaXpnGR0ptK5PXfxTUy48VkJOiglMIxlkYGs0w==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -9625,6 +10621,16 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, + "node_modules/react-js-cron": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-js-cron/-/react-js-cron-5.0.1.tgz", + "integrity": "sha512-qHUb/qWeMvXklGW6/hLtH9CjboRU7pu2hHxGGErUDTjHDOLn/b6CZHvVsx/e3ak+UObwf4Y0BHSQJzpn1JpvvA==", + "peerDependencies": { + "antd": ">=5.8.0", + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, "node_modules/react-onclickoutside": { "version": "6.13.1", "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz", @@ -9886,6 +10892,12 @@ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "peer": true + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -9932,12 +10944,12 @@ } }, "node_modules/rollup": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz", - "integrity": "sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", "dev": true, "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -9947,22 +10959,24 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.2", - "@rollup/rollup-android-arm64": "4.21.2", - "@rollup/rollup-darwin-arm64": "4.21.2", - "@rollup/rollup-darwin-x64": "4.21.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.2", - "@rollup/rollup-linux-arm-musleabihf": "4.21.2", - "@rollup/rollup-linux-arm64-gnu": "4.21.2", - "@rollup/rollup-linux-arm64-musl": "4.21.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.2", - "@rollup/rollup-linux-riscv64-gnu": "4.21.2", - "@rollup/rollup-linux-s390x-gnu": "4.21.2", - "@rollup/rollup-linux-x64-gnu": "4.21.2", - "@rollup/rollup-linux-x64-musl": "4.21.2", - "@rollup/rollup-win32-arm64-msvc": "4.21.2", - "@rollup/rollup-win32-ia32-msvc": "4.21.2", - "@rollup/rollup-win32-x64-msvc": "4.21.2", + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", "fsevents": "~2.3.2" } }, @@ -10065,6 +11079,15 @@ "loose-envify": "^1.1.0" } }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "peer": true, + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -10203,9 +11226,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } @@ -10234,6 +11257,12 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==", + "peer": true + }, "node_modules/string-natural-compare": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", @@ -10474,6 +11503,15 @@ "dev": true, "license": "MIT" }, + "node_modules/throttle-debounce": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", + "peer": true, + "engines": { + "node": ">=12.22" + } + }, "node_modules/tiny-case": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", @@ -10542,6 +11580,12 @@ "node": ">=8.0" } }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "peer": true + }, "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", @@ -10885,13 +11929,13 @@ } }, "node_modules/vite": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.2.tgz", - "integrity": "sha512-dDrQTRHp5C1fTFzcSaMxjk6vdpKvT+2/mIdE07Gw2ykehT49O0z/VHS3zZ8iV/Gh8BJJKHWOe5RjaNrW5xf/GA==", + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.41", + "postcss": "^8.4.43", "rollup": "^4.20.0" }, "bin": { @@ -11019,9 +12063,9 @@ } }, "node_modules/vite/node_modules/postcss": { - "version": "8.4.42", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.42.tgz", - "integrity": "sha512-hywKUQB9Ra4dR1mGhldy5Aj1X3MWDSIA1cEi+Uy0CjheLvP6Ual5RlwMCh8i/X121yEDLDIKBsrCQ8ba3FDMfQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "funding": [ { @@ -11039,8 +12083,8 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" diff --git a/package.json b/package.json index 28506e8e7b..7853acfbbd 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "react-hotkeys-hook": "^4.4.4", "react-i18next": "^15.0.1", "react-icons": "^5.2.1", + "react-js-cron": "^5.0.1", "react-redux": "^7.2.9", "react-router-dom": "^6.26.1", "react-select": "^5.8.0", diff --git a/src/components/events/LifeCyclePolicies.tsx b/src/components/events/LifeCyclePolicies.tsx index 19f5c46755..157afeb9ca 100644 --- a/src/components/events/LifeCyclePolicies.tsx +++ b/src/components/events/LifeCyclePolicies.tsx @@ -24,6 +24,8 @@ import { lifeCyclePoliciesTemplateMap } from "../../configs/tableConfigs/lifeCyc import { fetchEvents } from "../../slices/eventSlice"; import { setOffset } from "../../slices/tableSlice"; import { fetchSeries } from "../../slices/seriesSlice"; +import NewResourceModal from "../shared/NewResourceModal"; +import { fetchLifeCyclePolicyActions, fetchLifeCyclePolicyTargetTypes, fetchLifeCyclePolicyTimings } from "../../slices/lifeCycleDetailsSlice"; /** * This component renders the table view of policies @@ -32,6 +34,7 @@ const LifeCyclePolicies = () => { const { t } = useTranslation(); const dispatch = useAppDispatch(); const [displayNavigation, setNavigation] = useState(false); + const [displayNewPolicyModal, setNewPolicyModal] = useState(false); const user = useAppSelector(state => getUserInformation(state)); const policiesTotal = useAppSelector(state => getTotalLifeCyclePolicies(state)); @@ -77,6 +80,11 @@ const LifeCyclePolicies = () => { // Load policies on mount loadLifeCyclePolicies().then((r) => console.info(r)); + + // Fetch policies repeatedly + let fetchInterval = setInterval(loadLifeCyclePolicies, 5000); + + return () => clearInterval(fetchInterval); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -84,10 +92,32 @@ const LifeCyclePolicies = () => { setNavigation(!displayNavigation); }; + const showNewPolicyModal = async () => { + await dispatch(fetchLifeCyclePolicyActions()); + await dispatch(fetchLifeCyclePolicyTargetTypes()); + await dispatch(fetchLifeCyclePolicyTimings()); + + setNewPolicyModal(true); + }; + + const hideNewPolicyModal = () => { + setNewPolicyModal(false); + }; + return ( <>
+ { + /* Display modal for new event if add event button is clicked */ + displayNewPolicyModal && ( + + ) + } + {/* Include Burger-button menu*/} @@ -120,6 +150,15 @@ const LifeCyclePolicies = () => { )} + +
+ {hasAccess("ROLE_UI_EVENTS_CREATE", user) && ( + + )} +
diff --git a/src/components/events/partials/LifeCyclePolicyActionCell.tsx b/src/components/events/partials/LifeCyclePolicyActionCell.tsx index ce5df1e317..78de162c74 100644 --- a/src/components/events/partials/LifeCyclePolicyActionCell.tsx +++ b/src/components/events/partials/LifeCyclePolicyActionCell.tsx @@ -2,12 +2,13 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { useAppDispatch, useAppSelector } from "../../../store"; import { Tooltip } from "../../shared/Tooltip"; -import { LifeCyclePolicy } from "../../../slices/lifeCycleSlice"; +import { deleteLifeCyclePolicy, LifeCyclePolicy } from "../../../slices/lifeCycleSlice"; import DetailsModal from "../../shared/modals/DetailsModal"; import LifeCyclePolicyDetails from "./modals/LifeCyclePolicyDetails"; import { hasAccess } from "../../../utils/utils"; import { getUserInformation } from "../../../selectors/userInfoSelectors"; import { fetchLifeCyclePolicyDetails } from "../../../slices/lifeCycleDetailsSlice"; +import ConfirmModal from "../../shared/ConfirmModal"; /** * This component renders the title cells of series in the table view @@ -21,6 +22,7 @@ const LifeCyclePolicyActionCell = ({ const dispatch = useAppDispatch(); const [displayLifeCyclePolicyDetails, setLifeCyclePolicyDetails] = useState(false); + const [displayDeleteConfirmation, setDeleteConfirmation] = useState(false); const user = useAppSelector(state => getUserInformation(state)); @@ -34,6 +36,18 @@ const LifeCyclePolicyActionCell = ({ setLifeCyclePolicyDetails(false); }; + const hideDeleteConfirmation = () => { + setDeleteConfirmation(false); + }; + + const showDeleteConfirmation = async () => { + setDeleteConfirmation(true); + }; + + const deletingPolicy = (id: string) => { + dispatch(deleteLifeCyclePolicy(id)); + }; + return ( <> {/* view details location/recording */} @@ -55,6 +69,27 @@ const LifeCyclePolicyActionCell = ({ )} + + {/* delete policy */} + {hasAccess("ROLE_UI_LIFECYCLEPOLICY_DELETE", user) && ( + + + + + +
+ + )} + {/*
*/} + - - - + + )} + ); }; diff --git a/src/components/events/partials/ModalTabsAndPages/NewLifeCyclePolicyGeneralPage.tsx b/src/components/events/partials/ModalTabsAndPages/NewLifeCyclePolicyGeneralPage.tsx new file mode 100644 index 0000000000..532abdf59b --- /dev/null +++ b/src/components/events/partials/ModalTabsAndPages/NewLifeCyclePolicyGeneralPage.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import { FormikProps } from "formik"; +import WizardNavigationButtons from "../../../shared/wizard/WizardNavigationButtons"; +import LifeCyclePolicyGeneralFields from "../wizards/LifeCyclePolicyGeneralFields"; +import { LifeCyclePolicy, TargetFilter } from "../../../../slices/lifeCycleSlice"; + +/** + * This component renders the metadata page for new events and series in the wizards. + */ +const NewLifeCyclePolicyGeneralPage = ({ + formik, + nextPage, + header +}: { + formik: FormikProps, + nextPage: (values: T) => void, + header: string +}) => { + + return ( + <> +
+
+
+ {/* Table view containing input fields for metadata */} + +
+
+
+ + {/* Button for navigation to next page */} + + + ); +}; + +export default NewLifeCyclePolicyGeneralPage; diff --git a/src/components/events/partials/modals/LifeCyclePolicyDetails.tsx b/src/components/events/partials/modals/LifeCyclePolicyDetails.tsx index e818dd57c2..4cffc334ff 100644 --- a/src/components/events/partials/modals/LifeCyclePolicyDetails.tsx +++ b/src/components/events/partials/modals/LifeCyclePolicyDetails.tsx @@ -1,18 +1,32 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import ModalNavigation from "../../../shared/modals/ModalNavigation"; import { getLifeCyclePolicyDetails } from "../../../../selectors/lifeCycleDetailsSelectors"; import LifeCyclePolicyGeneralTab from "../ModalTabsAndPages/LifeCyclePolicyGeneralTab"; import LifeCyclePolicyDetailsAccessTab from "../ModalTabsAndPages/LifeCyclePolicyAccessTab"; -import { useAppSelector } from "../../../../store"; +import { useAppDispatch, useAppSelector } from "../../../../store"; +import { removeNotificationWizardForm } from "../../../../slices/notificationSlice"; +import { fetchLifeCyclePolicyActions, fetchLifeCyclePolicyTargetTypes, fetchLifeCyclePolicyTimings } from "../../../../slices/lifeCycleDetailsSlice"; /** * This component manages the tabs of the series details modal */ const LifeCyclePolicyDetails = () => { const [page, setPage] = useState(0); + const dispatch = useAppDispatch(); + + useEffect(() => { + dispatch(removeNotificationWizardForm()); + dispatch(fetchLifeCyclePolicyActions()); + dispatch(fetchLifeCyclePolicyTargetTypes()); + dispatch(fetchLifeCyclePolicyTimings()); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); const policy = useAppSelector(state => getLifeCyclePolicyDetails(state)); + // tracks, whether the policies are different to the initial value + const [policyChanged, setPolicyChanged] = useState(false); + // information about tabs const tabs = [ { @@ -23,7 +37,7 @@ const LifeCyclePolicyDetails = () => { { tabTranslation: "LIFECYCLE.POLICIES.DETAILS.TAB.ACCESSPOLICIES", accessRole: "ROLE_UI_LIFECYCLEPOLICIES_DETAILS_ACCESSPOLICIES_VIEW", - name: "WARNING: None of the changes you make here can be saved!", + name: "Access Policies" }, ]; @@ -42,8 +56,8 @@ const LifeCyclePolicyDetails = () => { false} + policyChanged={policyChanged} + setPolicyChanged={setPolicyChanged} /> } diff --git a/src/components/events/partials/wizards/LifeCyclePolicyGeneralFields.tsx b/src/components/events/partials/wizards/LifeCyclePolicyGeneralFields.tsx new file mode 100644 index 0000000000..042f2046f0 --- /dev/null +++ b/src/components/events/partials/wizards/LifeCyclePolicyGeneralFields.tsx @@ -0,0 +1,475 @@ +import React, { useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { FieldArray, FieldProps, FormikProps } from "formik"; +import { Field } from "../../../shared/Field"; +import RenderField from "../../../shared/wizard/RenderField"; +import { ALL_TARGET_FILTER_TYPES, LifeCyclePolicy, TargetFilter } from "../../../../slices/lifeCycleSlice"; +import { useAppDispatch, useAppSelector } from "../../../../store"; +import { getLifeCyclePolicyActions, getLifeCyclePolicyTargetTypes, getLifeCyclePolicyTimings } from "../../../../selectors/lifeCycleDetailsSelectors"; +import DropDown from "../../../shared/DropDown"; +import { getEventMetadata } from "../../../../selectors/eventSelectors"; +import { fetchEventMetadata } from "../../../../slices/eventSlice"; + +/** + * This component renders the metadata page for new events and series in the wizards. + */ +// interface RequiredFormProps { +// sourceMode: string, +// processingWorkflow: string, +// } + +const LifeCyclePolicyGeneralFields = ({ + formik, + isNew, +}: { + formik: FormikProps, + isNew: boolean +}) => { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + + const actions = useAppSelector(state => getLifeCyclePolicyActions(state)); + const targetTypes = useAppSelector(state => getLifeCyclePolicyTargetTypes(state)); + const timings = useAppSelector(state => getLifeCyclePolicyTimings(state)); + const metadataFields = useAppSelector(state => getEventMetadata(state)); + + useEffect(() => { + dispatch(fetchEventMetadata()) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + const ADDITIONAL_TARGET_FILTER_KEYS_EVENTS = [ + { + id: 'series_name', + type: 'text', + collection: undefined + }, + { + id: 'presenter', + type: 'text', + collection: undefined + }, + { + id: 'start_date', + type: 'date', + collection: undefined + }, + { + id: 'end_date', + type: 'date', + collection: undefined + }, + { + id: 'created', + type: 'date', + collection: undefined + }, + { + id: 'source', + type: 'text', + collection: undefined + }, + { + id: 'rights', + type: 'text', + collection: undefined + }, + { + id: 'location', + type: 'text', + collection: undefined + }, + ] + + const eventFilterOptions: { id: string, type: string, collection?: unknown }[] = [] + for (const field of metadataFields.fields) { + eventFilterOptions.push(field) + } + for (const field of ADDITIONAL_TARGET_FILTER_KEYS_EVENTS) { + eventFilterOptions.push(field) + } + + const createTargetFilter = (): TargetFilter => { + return { + value: "", + type: "SEARCH", + must: true + } + } + + const filterOptions = (targetType: string) => { + switch (targetType) { + case "EVENT": + return eventFilterOptions + default: + return [] + } + } + + return ( + <> +
+
{t("LIFECYCLE.POLICIES.NEW.GENERAL.CAPTION")}
+ + + + + + + + + + + + {!isNew && + + + + + } + + + + + + + + + + + + + + + + + + + + + {!isNew && + + + + + } + + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TITLE")}* + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ISACTIVE")}* + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ISCREATEDFROMCONFIG")} + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETTYPE")}* + ({ value: element, name: element }) ), + id: "language", + }} + component={RenderField} + /> +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TIMING")}* + ({ value: element, name: element }) ), + id: "language", + }} + component={RenderField} + /> +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTION")}* + ({ value: element, name: element }) ), + id: "language" + }} + component={RenderField} + /> +
+ {t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTIONDATE")} + {formik.values.timing === "SPECIFIC_DATE" && *} + + +
+ {t("LIFECYCLE.POLICIES.DETAILS.GENERAL.CRONTRIGGER")} + {formik.values.timing === "REPEATING" && *} + + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ID")} + {formik.values.id} +
+
+ +
+ + + {/* Target Filters like the ACLs + Can we make "key" a dropdown? + Type of "Value" should depend on key, e.g. for key "start_date" show a date picker + */} +
+
+ { t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETFILTERS.CAPTION") } +
+ + + {/* column headers */} + + + + + + + + + + + + + {({ replace, remove, push }) => ( + <> + {Object.entries(formik.values.targetFiltersArray).map(([key, filter], index) => { + return( + + + + + + + + ) + })} + + + + + )} + + +
+ { t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETFILTERS.FILTER") } + + { t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETFILTERS.VALUE") } + + { t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETFILTERS.TYPE") } + + { t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETFILTERS.MUST") } + + { t("EVENTS.EVENTS.DETAILS.ACCESS.ACCESS_POLICY.ACTION") } +
+ e.id)} + creatable={true} + clearFieldName={`targetFiltersArray.${key}.value`} + component={DropdownField} + /> + + + + + + + +
+ +
+
+ + {formik.values.action === "START_WORKFLOW" && +
+
+ { t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTIONPARAMETERS.CAPTION") } +
+ + + + + + + + + + + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTIONPARAMETERS.WORKFLOW_ID")}* + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTIONPARAMETERS.WORKFLOW_PARAMETERS")} + + {/* Using our "WorkflowConfig" component would be nice, but it does not allow us to add or remove config options */} + {/* */} +
+
+ } + + ); +}; + + +export default LifeCyclePolicyGeneralFields; + +const DropdownField = ({ + field, + form: { setFieldValue }, + value, + values, + clearFieldName, + creatable = false +}: { + field: FieldProps["field"] + form: FieldProps["form"] + value: string, + values: string[] + clearFieldName: string + creatable: boolean +}) => { + const { t } = useTranslation(); + + return ( + { + setFieldValue(clearFieldName, undefined) + element && setFieldValue(field.name, element.value) + }} + placeholder={`-- ${t("SELECT_NO_OPTION_SELECTED")} --`} + creatable={creatable} + /> + ) +}; + +const getTargetFilterRenderType = (filterName: string, targetFilterOptions: { id: string, type: string, collection?: unknown }[] ) => { + const option = targetFilterOptions.find(e => e.id === filterName); + if (option === undefined) { + return "text"; + } + // Simplify types like "long_text" or "mixed_text" + if (option.type.includes("text")) { + return "text"; + } + return option.type; +} + +const getTargetFilterRenderCollection = (filterName: string, targetFilterOptions: { id: string, type: string, collection?: unknown }[] ) => { + const option = targetFilterOptions.find(e => e.id === filterName); + return option !== undefined ? option.collection : undefined +} diff --git a/src/components/events/partials/wizards/NewLifeCyclePolicySummary.tsx b/src/components/events/partials/wizards/NewLifeCyclePolicySummary.tsx new file mode 100644 index 0000000000..be069c305b --- /dev/null +++ b/src/components/events/partials/wizards/NewLifeCyclePolicySummary.tsx @@ -0,0 +1,112 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import AccessSummaryTable from "./summaryTables/AccessSummaryTable"; +import WizardNavigationButtons from "../../../shared/wizard/WizardNavigationButtons"; +import { FormikProps } from "formik"; +import { renderValidDate } from "../../../../utils/dateUtils"; +import { initialFormValuesNewLifeCyclePolicy } from "../../../../configs/modalConfig"; + +/** + * This component renders the summary page for new series in the new series wizard. + */ +// interface RequiredFormProps { + +// } + +const NewLifeCyclePolicySummary = ({ + formik, + previousPage, +}: { + formik: FormikProps, + previousPage: (values: T, twoPagesBack?: boolean) => void, +}) => { + const { t } = useTranslation(); + + return ( + <> +
+
+
+ +
+
{t("LIFECYCLE.POLICIES.NEW.CAPTION")}
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ))} + + + + + + + + + } + + + +
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TITLE")}{formik.values.title}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ISACTIVE")}{formik.values.isActive}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETTYPE")}{formik.values.targetType}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TIMING")}{formik.values.timing}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTION")}{formik.values.action}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTIONDATE")}{t("dateFormats.dateTime.medium", { dateTime: renderValidDate(formik.values.actionDate) } )}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.CRONTRIGGER")}{formik.values.cronTrigger}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.TARGETFILTERS.CAPTION")} + {formik.values.targetFiltersArray.map((filter) => ( +
{filter.filter}{filter.value}{filter.type}{filter.must.toString()}
{t("LIFECYCLE.POLICIES.DETAILS.GENERAL.ACTIONPARAMETERS.CAPTION")} + {formik.values.action === "START_WORKFLOW" && +
{formik.values.actionParameters.workflowId}{formik.values.actionParameters.workflowParameters}
+
+
+ {/*Summary access configuration*/} + + +
+
+
+ + {/* Button for navigation to next page and previous page */} + + + ); +}; + +export default NewLifeCyclePolicySummary; diff --git a/src/components/events/partials/wizards/NewLifeCyclePolicyWizard.tsx b/src/components/events/partials/wizards/NewLifeCyclePolicyWizard.tsx new file mode 100644 index 0000000000..73b59719bf --- /dev/null +++ b/src/components/events/partials/wizards/NewLifeCyclePolicyWizard.tsx @@ -0,0 +1,177 @@ +import React, { useEffect, useState } from "react"; +import { Formik } from "formik"; +import NewAccessPage from "../ModalTabsAndPages/NewAccessPage"; +import WizardStepperEvent from "../../../shared/wizard/WizardStepperEvent"; +import { useAppDispatch, useAppSelector } from "../../../../store"; +import { getUserInformation } from "../../../../selectors/userInfoSelectors"; +import { UserInfoState } from "../../../../slices/userInfoSlice"; +import { postNewLifeCyclePolicy } from "../../../../slices/lifeCycleSlice"; +import NewLifeCyclePolicyGeneralPage from "../ModalTabsAndPages/NewLifeCyclePolicyGeneralPage"; +import NewLifeCyclePolicySummary from "./NewLifeCyclePolicySummary"; +import { LifeCyclePolicySchema } from "../../../../utils/validate"; +import { initialFormValuesNewLifeCyclePolicy } from "../../../../configs/modalConfig"; +import { parseTargetFiltersForSubmit } from "../../../../utils/lifeCycleUtils"; + +/** + * This component manages the pages of the new event wizard and the submission of values + */ +const NewLifeCyclePolicyWizard = ({ + close, +}: { + close: () => void +}) => { + const dispatch = useAppDispatch(); + + const user = useAppSelector(state => getUserInformation(state)); + + const initialValues = getInitialValues(user); + + const [page, setPage] = useState(0); + const [snapshot, setSnapshot] = useState(initialValues); + const [pageCompleted, setPageCompleted] = useState<{ [key: number]: boolean }>({}); + + // Caption of steps used by Stepper + const steps = [ + { + translation: "LIFECYCLE.POLICIES.NEW.GENERAL.CAPTION", + name: "general", + hidden: false, + }, + { + translation: "EVENTS.EVENTS.NEW.ACCESS.CAPTION", + name: "access", + hidden: false, + }, + { + translation: "EVENTS.EVENTS.NEW.SUMMARY.CAPTION", + name: "summary", + hidden: false, + }, + ]; + + const nextPage = (values: typeof initialValues) => { + setSnapshot(values); + + // set page as completely filled out + let updatedPageCompleted = pageCompleted; + updatedPageCompleted[page] = true; + setPageCompleted(updatedPageCompleted); + + let newPage = page; + do { + newPage = newPage + 1; + } while(steps[newPage] && steps[newPage].hidden); + if (steps[newPage]) { + setPage(newPage) + } + }; + + const previousPage = (values: typeof initialValues) => { + setSnapshot(values); + + let newPage = page; + do { + newPage = newPage - 1; + } while(steps[newPage] && steps[newPage].hidden); + if (steps[newPage]) { + setPage(newPage) + } + }; + + const handleSubmit = (values: typeof initialValues) => { + const fixedValues = { + ...values, + targetFilters: parseTargetFiltersForSubmit(values.targetFiltersArray), + accessControlEntries: values.acls + } + if (fixedValues.action === "START_WORKFLOW") { + fixedValues.actionParameters["workflowParameters"] = JSON.parse(values.actionParameters["workflowParameters"] as string) + } + // values["accessControlEntries"] = values.acls; + const response = dispatch(postNewLifeCyclePolicy(fixedValues)); + console.info(response); + close(); + }; + + return ( + <> + handleSubmit(values)} + > + {/* Render wizard pages depending on current value of page variable */} + {(formik) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + useEffect(() => { + formik.validateForm(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [page]); + + return ( + <> + {/* Stepper that shows each step of wizard as header */} + +
+ {page === 0 && ( + + )} + {page === 1 && ( + + )} + {page === 2 && ( + + )} +
+ + ); + }} +
+ + ); +} + +// Transform all initial values needed from information provided by backend +const getInitialValues = ( + user: UserInfoState +) => { + let initialValues = initialFormValuesNewLifeCyclePolicy; + + initialValues["acls"] = [ + { + role: user.userRole, + read: true, + write: true, + actions: [], + }, + ]; + + return initialValues; +}; + +export default NewLifeCyclePolicyWizard; diff --git a/src/components/events/partials/wizards/RenderWorkflowConfig.tsx b/src/components/events/partials/wizards/RenderWorkflowConfig.tsx index 3ea294a170..9687510502 100644 --- a/src/components/events/partials/wizards/RenderWorkflowConfig.tsx +++ b/src/components/events/partials/wizards/RenderWorkflowConfig.tsx @@ -6,7 +6,7 @@ import { getWorkflowDefById, } from "../../../../selectors/workflowSelectors"; import { useAppSelector } from "../../../../store"; -import { FieldSetField } from "../../../../slices/workflowSlice"; +import { ConfigurationPanelField, FieldSetField } from "../../../../slices/workflowSlice"; /** * This component renders the configuration panel for the selected workflow in the processing step of the new event @@ -32,10 +32,28 @@ const RenderWorkflowConfig = ({ const configPanel = !!workflowDef && workflowDef.configuration_panel_json ? workflowDef.configuration_panel_json : []; - const description = !!workflowDef && workflowDef.description + const description = !!workflowDef && workflowDef.description && !displayDescription ? workflowDef.description : ""; + return ( + + ); +}; + +export const WorkflowConfig = ({ + formik, + configPanel, + description +}: { + formik: FormikProps + configPanel: string | ConfigurationPanelField[] + description: string +}) => { const descriptionBoxStyle = { margin: "15px 0 0 0", position: "relative" as const, @@ -55,7 +73,7 @@ const RenderWorkflowConfig = ({ return ( <> - {displayDescription && description.length > 0 && ( + {description.length > 0 && (
{description.trim()}
diff --git a/src/components/shared/ConfirmModal.tsx b/src/components/shared/ConfirmModal.tsx index 91395fab88..4a4262dc23 100644 --- a/src/components/shared/ConfirmModal.tsx +++ b/src/components/shared/ConfirmModal.tsx @@ -15,7 +15,7 @@ const ConfirmModal = ({ deleteWithCautionMessage = "", }: { close: () => void, - resourceType: "EVENT" | "SERIES" | "LOCATION" | "USER" | "GROUP" | "ACL" | "THEME", + resourceType: "EVENT" | "SERIES" | "LOCATION" | "USER" | "GROUP" | "ACL" | "THEME" | "LIFECYCLE_POLICY", resourceName: string, resourceId: T, deleteMethod: (id: T) => void, diff --git a/src/components/shared/DropDown.tsx b/src/components/shared/DropDown.tsx index 2c746a6307..dfa3d0c922 100644 --- a/src/components/shared/DropDown.tsx +++ b/src/components/shared/DropDown.tsx @@ -18,7 +18,7 @@ import CreatableSelect from "react-select/creatable"; * - Creating typescript types for each "type" is moot atm, as a lot of them (i.e. capture agents) are not properly typed yet * I would suggest waiting with typing options until all of its inputs are properly typed */ -export type DropDownType = "language" | "isPartOf" | "license" | "captureAgent" | "aclRole" | "workflow" | "aclTemplate" | "newTheme" | "comment" | "theme" | "time" | "filter"; +export type DropDownType = "language" | "isPartOf" | "license" | "captureAgent" | "aclRole" | "workflow" | "aclTemplate" | "newTheme" | "comment" | "theme" | "time" | "filter" | "policyAction"; /** * This component provides a bar chart for visualising (statistics) data diff --git a/src/components/shared/NewResourceModal.tsx b/src/components/shared/NewResourceModal.tsx index 848e48df43..d47f022c7c 100644 --- a/src/components/shared/NewResourceModal.tsx +++ b/src/components/shared/NewResourceModal.tsx @@ -8,6 +8,7 @@ import NewGroupWizard from "../users/partials/wizard/NewGroupWizard"; import NewUserWizard from "../users/partials/wizard/NewUserWizard"; import { useHotkeys } from "react-hotkeys-hook"; import { availableHotkeys } from "../../configs/hotkeysConfig"; +import NewLifeCyclePolicyWizard from "../events/partials/wizards/NewLifeCyclePolicyWizard"; /** * This component renders the modal for adding new resources @@ -17,7 +18,7 @@ const NewResourceModal = ({ resource }: { handleClose: () => void, - resource: "events" | "series" | "user" | "group" | "acl" | "themes" + resource: "events" | "series" | "user" | "group" | "acl" | "themes" | "lifecyclepolicy" }) => { const { t } = useTranslation(); @@ -56,6 +57,9 @@ const NewResourceModal = ({ {resource === "user" && (

{t("USERS.USERS.DETAILS.NEWCAPTION")}

)} + {resource === "lifecyclepolicy" && ( +

{t("LIFECYCLE.POLICIES.NEW.CAPTION")}

+ )}
{resource === "events" && ( //New Event Wizard @@ -81,6 +85,10 @@ const NewResourceModal = ({ // New User Wizard )} + {resource === "lifecyclepolicy" && ( + // New LifeCyclePolicy Wizard + + )} ); diff --git a/src/components/shared/wizard/RenderField.tsx b/src/components/shared/wizard/RenderField.tsx index 1a72718c97..6e8a979847 100644 --- a/src/components/shared/wizard/RenderField.tsx +++ b/src/components/shared/wizard/RenderField.tsx @@ -10,6 +10,8 @@ import { parseISO } from "date-fns"; import { FieldProps } from "formik"; import { MetadataField } from "../../../slices/eventSlice"; import { renderValidDate } from "../../../utils/dateUtils"; +import Cron from "react-js-cron"; +import 'react-js-cron/dist/styles.css' const childRef = React.createRef(); /** @@ -23,7 +25,7 @@ const RenderField = ({ isFirstField = false, }: { field: FieldProps["field"] - metadataField: MetadataField + metadataField: { type: string, collection: { [key: string]: unknown }[], required: boolean, id: string }, //MetadataField form: FieldProps["form"] showCheck?: boolean, isFirstField?: boolean, @@ -129,6 +131,17 @@ const RenderField = ({ handleKeyDown={handleKeyDown} /> )} + {metadataField.type === "cron" && ( + + )} ); }; @@ -229,7 +242,7 @@ const EditableSingleSelect = ({ showCheck, }: { field: FieldProps["field"] - metadataField: MetadataField + metadataField: { type: string, collection: { [key: string]: unknown }[], required: boolean, id: string }, //MetadataField text: string editMode: boolean | undefined setEditMode: (e: boolean) => void @@ -427,4 +440,55 @@ const EditableSingleValueTime = ({ ); }; +const EditableCronValue = ({ + field, + form: { initialValues, setFieldValue }, + text, + editMode, + setEditMode, + showCheck, + handleKeyDown, +} : { + field: FieldProps["field"] + form: FieldProps["form"] + text: string + editMode: boolean | undefined + setEditMode: (e: boolean) => void + showCheck?: boolean, + handleKeyDown: (event: React.KeyboardEvent, type: string) => void +}) => { + + return editMode ? ( + // TODO: Figure out a way to set EditMode to false again + // As of now, selecting a value in one of the dropdowns will cause EditMode + // to be set to false, without the selected value actually being set. +
setEditMode(false)} + onKeyDown={(e) => handleKeyDown(e, "cron")} + // ref={childRef} + > + setFieldValue(field.name, value)} + /> +
+ ) : ( +
setEditMode(true)} className="show-edit"> + {text || ""} +
+ + {showCheck && ( + + )} +
+
+ ) +}; + + export default RenderField; diff --git a/src/components/shared/wizard/RenderMultiField.tsx b/src/components/shared/wizard/RenderMultiField.tsx index b9415afe3a..d7396a5d2a 100644 --- a/src/components/shared/wizard/RenderMultiField.tsx +++ b/src/components/shared/wizard/RenderMultiField.tsx @@ -28,7 +28,7 @@ const RenderMultiField = ({ // Temporary storage for value user currently types in const [inputValue, setInputValue] = useState(""); - let fieldValue = [...field.value]; + let fieldValue = field.value ? [...field.value] : []; // Handle change of value user currently types in const handleChange = (e: React.ChangeEvent) => { diff --git a/src/configs/modalConfig.ts b/src/configs/modalConfig.ts index 1f155f8352..2d4ad7f108 100644 --- a/src/configs/modalConfig.ts +++ b/src/configs/modalConfig.ts @@ -5,6 +5,7 @@ import { TobiraPage } from "../slices/seriesSlice"; import { initArray } from "../utils/utils"; import { EditedEvents, Event, UploadAssetsTrack } from "../slices/eventSlice"; import { Role } from "../slices/aclSlice"; +import { TargetFilter } from "../slices/lifeCycleSlice"; // Context for notifications shown in modals export const NOTIFICATION_CONTEXT = "modal-form"; @@ -207,3 +208,33 @@ export const initialFormValuesEditScheduledEvents: { editedEvents: [], changedEvents: [], }; + +export const initialFormValuesNewLifeCyclePolicy: { + title: string, + isActive: boolean, + isCreatedFromConfig: boolean, + targetType: string, + timing: string, + action: string, + actionDate: string, + cronTrigger: string, + actionParameters: { [key: string]: unknown } + acls: TransformedAcl[] + targetFiltersArray: (TargetFilter & { filter: string })[], +} = { + title: "", + isActive: true, + isCreatedFromConfig: false, + targetType: "EVENT", + timing: "SPECIFIC_DATE", + action: "START_WORKFLOW", + actionDate: "", + cronTrigger: "", + actionParameters: { + workflowId: "noop", + workflowParameters: `{"straightToPublishing": true}` + }, + + acls: [], + targetFiltersArray: [], +}; diff --git a/src/i18n/org/opencastproject/adminui/languages/lang-en_US.json b/src/i18n/org/opencastproject/adminui/languages/lang-en_US.json index dd3c50013f..d9589dac19 100644 --- a/src/i18n/org/opencastproject/adminui/languages/lang-en_US.json +++ b/src/i18n/org/opencastproject/adminui/languages/lang-en_US.json @@ -119,7 +119,8 @@ "GROUP": "The following group will be deleted", "USER": "The following user will be deleted", "THEME": "The following theme will be deleted", - "LOCATION": "The following location will be deleted" + "LOCATION": "The following location will be deleted", + "LIFECYCLE_POLICY": "The following lifeCycle policy will be deleted" }, "NAME": "Name" }, @@ -188,6 +189,10 @@ "EVENTS_NOT_DELETED_NOT_AUTHORIZED": "The event(s) could not be deleted, because you don't have the permission to do so.", "SERIES_DELETED": "The series has been deleted", "SERIES_NOT_DELETED": "The series could not be deleted", + "LIFECYCLE_POLICY_ADDED": "The lifeCycle policy has been created", + "LIFECYCLE_POLICY_NOT_SAVED": "The lifeCycle policy could not be saved", + "LIFECYCLE_POLICY_DELETED": "The lifeCycle policy has been deleted", + "LIFECYCLE_POLICY_NOT_DELETED": "The lifeCycle policy could not be deleted", "LOCATION_DELETED": "The location has been deleted", "LOCATION_NOT_DELETED": "The location could not be deleted", "LOCATION_NOT_DELETED_NOT_AUTHORIZED": "The location could not be deleted, because you don't have the permission to do so.", @@ -1234,7 +1239,15 @@ "TIMING": "Timing", "TITLE": "Title", "TOOLTIP": { - "DETAILS": "LifeCycle Policy Details" + "DETAILS": "LifeCycle Policy Details", + "DELETE": "Delete LifeCycle Policy" + }, + "ADD_POLICY": "Add LifeCycle Policy" + }, + "NEW": { + "CAPTION": "Create LifeCycle Policy", + "GENERAL": { + "CAPTION": "General" } }, "DETAILS": { @@ -1242,16 +1255,31 @@ "GENERAL": { "ACTION": "Action", "ACTIONDATE": "Action Date", - "ACTIONPARAMETERS": "Action Parameters", + "ACTIONPARAMETERS": { + "CAPTION": "Action Parameters", + "WORKFLOW_ID": "Workflow ID", + "WORKFLOW_PARAMETERS": "Workflow Parameters" + }, "CAPTION": "LifeCycle Policy Details", "CRONTRIGGER": "Cron Trigger", "ID": "Identifier", "ISACTIVE": "Active", "ISCREATEDFROMCONFIG": "Created from Config", "TARGETTYPE": "Target Type", - "TARGETFILTERS": "Target Filters", + "TARGETFILTERS": { + "CAPTION": "Target Filters", + "FILTER": "Filter", + "VALUE": "Value", + "TYPE": "Type", + "MUST": "Must", + "NEW": "New Filter" + }, "TIMING": "Timing", - "TITLE": "Title" + "TITLE": "Title", + "NOTE": { + "TITLE": "A note on editing LifeCycle Policies", + "MESSAGE": "The same policy cannot affect the same target multiple times. Depending on your goals, creating a new policy may be required." + } }, "ACCESS": { "LABEL": "Select a template", diff --git a/src/selectors/lifeCycleDetailsSelectors.ts b/src/selectors/lifeCycleDetailsSelectors.ts index 364368819a..8b279abb40 100644 --- a/src/selectors/lifeCycleDetailsSelectors.ts +++ b/src/selectors/lifeCycleDetailsSelectors.ts @@ -5,3 +5,6 @@ import { RootState } from "../store"; */ export const getLifeCyclePolicyDetails = (state: RootState) => state.lifeCyclePolicyDetails; export const getLifeCyclePolicyDetailsAcl = (state: RootState) => state.lifeCyclePolicyDetails.accessControlEntries; +export const getLifeCyclePolicyActions = (state: RootState) => state.lifeCyclePolicyDetails.actionsEnum; +export const getLifeCyclePolicyTargetTypes = (state: RootState) => state.lifeCyclePolicyDetails.targetTypesEnum; +export const getLifeCyclePolicyTimings = (state: RootState) => state.lifeCyclePolicyDetails.timingsEnum; diff --git a/src/slices/lifeCycleDetailsSlice.ts b/src/slices/lifeCycleDetailsSlice.ts index 2bba3cda56..0a8407afe4 100644 --- a/src/slices/lifeCycleDetailsSlice.ts +++ b/src/slices/lifeCycleDetailsSlice.ts @@ -5,6 +5,8 @@ import { LifeCyclePolicy } from './lifeCycleSlice'; import { TransformedAcl } from './aclDetailsSlice'; import { createPolicy } from '../utils/resourceUtils'; import { Ace } from './aclSlice'; +import { addNotification } from './notificationSlice'; + /** * This file contains redux reducer for actions affecting the state of a lifeCyclePolicy/capture agent @@ -12,6 +14,10 @@ import { Ace } from './aclSlice'; interface LifeCyclePolicyDetailsState extends LifeCyclePolicy { statusLifeCyclePolicyDetails: 'uninitialized' | 'loading' | 'succeeded' | 'failed', errorLifeCyclePolicyDetails: SerializedError | null, + + actionsEnum: string[], + targetTypesEnum: string[], + timingsEnum: string[], } // Initial state of lifeCyclePolicy details in redux store @@ -29,7 +35,11 @@ const initialState: LifeCyclePolicyDetailsState = { actionDate: "", cronTrigger: "", targetFilters: {}, - accessControlEntries: [] + accessControlEntries: [], + + actionsEnum: [], + targetTypesEnum: [], + timingsEnum: [], }; // fetch details of certain lifeCyclePolicy from server @@ -70,6 +80,27 @@ export const fetchLifeCyclePolicyDetails = createAppAsyncThunk('lifeCyclePolicyD return data; }); +export const fetchLifeCyclePolicyActions = createAppAsyncThunk('lifeCyclePolicyDetails/fetchLifeCyclePolicyActions', async () => { + const res = await axios.get(`/api/lifecyclemanagement/policies/actions`); + const data = res.data; + + return data; +}); + +export const fetchLifeCyclePolicyTargetTypes = createAppAsyncThunk('lifeCyclePolicyDetails/fetchLifeCyclePolicyTargetTypes', async () => { + const res = await axios.get(`/api/lifecyclemanagement/policies/targettypes`); + const data = res.data; + + return data; +}); + +export const fetchLifeCyclePolicyTimings = createAppAsyncThunk('lifeCyclePolicyDetails/fetchLifeCyclePolicyTimings', async () => { + const res = await axios.get(`/api/lifecyclemanagement/policies/timings`); + const data = res.data; + + return data; +}); + // Dummy function for compatability export const fetchLifeCyclePolicyDetailsAcls = createAppAsyncThunk('lifeCyclePolicyDetails/fetchLifeCyclePolicyDetailsAcls', async (id: string, {getState}) => { const state = getState(); @@ -81,7 +112,47 @@ export const updateLifeCyclePolicyAccess = createAppAsyncThunk('lifeCyclePolicyD id: string, policies: { acl: { ace: Ace[] } } }, {dispatch}) => { - return false; + const { id, policies } = params; + + let data = new URLSearchParams(); + data.append("accessControlEntries", JSON.stringify(policies.acl.ace)); + + axios.put(`/api/lifecyclemanagement/policies/${id}`, data) + .then((response) => { + console.info(response); + dispatch(addNotification({type: "success", key: "LIFECYCLEPOLICY_ADDED"})); + return true; + }) + .catch((response) => { + console.error(response); + dispatch(addNotification({type: "error", key: "LIFECYCLEPOLICY_NOT_SAVED"})); + return false; + }); +}); + +export const updateLifeCyclePolicy = createAppAsyncThunk('lifeCyclePolicyDetails/updateLifeCyclePolicy', async (policy: LifeCyclePolicy, {dispatch}) => { + let data = new URLSearchParams(); + + Object.entries(policy).forEach(([key, value]) => { + let stringified = value + if (stringified instanceof Date) { + stringified = stringified.toJSON() + } + else if (stringified === Object(stringified)) { + stringified = JSON.stringify(stringified) + } + data.append(key, stringified); + }) + + axios.put(`/api/lifecyclemanagement/policies/${policy.id}`, data) + .then((response) => { + console.info(response); + dispatch(addNotification({type: "success", key: "LIFECYCLEPOLICY_ADDED"})); + }) + .catch((response) => { + console.error(response); + dispatch(addNotification({type: "error", key: "LIFECYCLEPOLICY_NOT_SAVED"})); + }); }); const lifeCyclePolicyDetailsSlice = createSlice({ @@ -126,7 +197,25 @@ const lifeCyclePolicyDetailsSlice = createSlice({ .addCase(fetchLifeCyclePolicyDetails.rejected, (state, action) => { state.statusLifeCyclePolicyDetails = 'failed'; state.errorLifeCyclePolicyDetails = action.error; - }); + }) + .addCase(fetchLifeCyclePolicyActions.fulfilled, (state, action: PayloadAction< + LifeCyclePolicyDetailsState["actionsEnum"] + >) => { + const actionsEnum = action.payload; + state.actionsEnum = actionsEnum; + }) + .addCase(fetchLifeCyclePolicyTargetTypes.fulfilled, (state, action: PayloadAction< + LifeCyclePolicyDetailsState["actionsEnum"] + >) => { + const targetTypesEnum = action.payload; + state.targetTypesEnum = targetTypesEnum; + }) + .addCase(fetchLifeCyclePolicyTimings.fulfilled, (state, action: PayloadAction< + LifeCyclePolicyDetailsState["actionsEnum"] + >) => { + const timingsEnum = action.payload; + state.timingsEnum = timingsEnum; + }) } }); diff --git a/src/slices/lifeCycleSlice.ts b/src/slices/lifeCycleSlice.ts index cfa4e78192..32b8aa589e 100644 --- a/src/slices/lifeCycleSlice.ts +++ b/src/slices/lifeCycleSlice.ts @@ -2,30 +2,35 @@ import { PayloadAction, SerializedError, createSlice } from '@reduxjs/toolkit' import { TableConfig } from "../configs/tableConfigs/aclsTableConfig"; import { lifeCyclePolicyTableConfig } from "../configs/tableConfigs/lifeCyclePoliciesTableConfig"; import axios from 'axios'; -import { getURLParams } from '../utils/resourceUtils'; +import { getURLParams, prepareAccessPolicyRulesForPost } from '../utils/resourceUtils'; import { createAppAsyncThunk } from '../createAsyncThunkWithTypes'; import { TransformedAcl } from './aclDetailsSlice'; +import { addNotification } from './notificationSlice'; -type LifeCyclePolicyTiming = "SPECIFIC_DATE" | "REPEATING" | "ALWAYS"; -type LifeCyclePolicyAction = "START_WORKFLOW" -type LifeCyclePolicyTargetType = "EVENT" +// type LifeCyclePolicyTiming = "SPECIFIC_DATE" | "REPEATING" | "ALWAYS"; +// type LifeCyclePolicyAction = "START_WORKFLOW" +// type LifeCyclePolicyTargetType = "EVENT" +export type TargetFilter = { + value: string | string[], + type: TargetFiltersType, + must: boolean +} +export const ALL_TARGET_FILTER_TYPES = ['SEARCH', 'WILDCARD', 'GREATER_THAN', 'LESS_THAN'] as const; +type TargetFilterTypesTuple = typeof ALL_TARGET_FILTER_TYPES; +type TargetFiltersType = TargetFilterTypesTuple[number]; export type LifeCyclePolicy = { actionParameters: { [key: string]: unknown }, // JSON. Variable, depends on action - timing: LifeCyclePolicyTiming, - action: LifeCyclePolicyAction, - targetType: LifeCyclePolicyTargetType, + timing: string, + action: string, + targetType: string, id: string, title: string, isActive: boolean, isCreatedFromConfig: boolean, actionDate: string, // Date cronTrigger: string, - targetFilters: { [key: string]: { - value: string, - type: "SEARCH" | "WILDCARD" | "GREATER_THAN" | "LESS_THAN", - must: boolean - }}, + targetFilters: { [key: string]: TargetFilter }, accessControlEntries: TransformedAcl[] } @@ -65,6 +70,71 @@ export const fetchLifeCyclePolicies = createAppAsyncThunk('lifeCycle/fetchLifeCy return res.data; }); +export const postNewLifeCyclePolicy = createAppAsyncThunk('lifeCycle/postNewLifeCyclePolicy', async ( + policy: { + actionParameters: { [key: string]: unknown }, + timing: string, + action: string, + targetType: string, + title: string, + isActive: boolean, + actionDate: string, + cronTrigger: string, + targetFilters: { [key: string]: TargetFilter }, + accessControlEntries: TransformedAcl[] + }, + { dispatch } +) => { + let data = new URLSearchParams(); + + // Format filter collections + // for (const filterName in policy.targetFilters) { + // // policy.targetFilters[filterName] + // if (hasOwnProperty(TARGET_FILTER_KEYS_EVENTS, filterName) + // && TARGET_FILTER_KEYS_EVENTS[filterName].collection) { + // policy.targetFilters[filterName].value = policy.targetFilters[filterName].value.toString() + // } + // } + + // Stringify + Object.entries(policy).forEach(([key, value]) => { + let stringified = value + if (stringified instanceof Date) { + stringified = stringified.toJSON() + } + else if (stringified === Object(stringified)) { + stringified = JSON.stringify(stringified) + } + data.append(key, stringified); + }) + + data.delete("accessControlEntries"); + data.append("accessControlEntries", JSON.stringify(prepareAccessPolicyRulesForPost(policy.accessControlEntries).acl.ace)) + + axios.post(`/api/lifecyclemanagement/policies`, data) + .then((res) => { + console.info(res); + dispatch(addNotification({type: "success", key: "LIFECYCLE_POLICY_ADDED"})); + }) + .catch((res) => { + console.error(res); + dispatch(addNotification({type: "error", key: "LIFECYCLE_POLICY_NOT_SAVED"})); + }); +}); + +export const deleteLifeCyclePolicy = createAppAsyncThunk('lifeCycle/fetchLifeCyclePolicies', async (id: string, { dispatch }) => { + axios + .delete(`/api/lifecyclemanagement/policies/${id}`) + .then((res) => { + console.info(res); + dispatch(addNotification({type: "success", key: "LIFECYCLE_POLICY_DELETED"})); + }) + .catch((res) => { + console.error(res); + dispatch(addNotification({type: "error", key: "LIFECYCLE_POLICY_NOT_DELETED"})); + }); +}); + const lifeCycleSlice = createSlice({ name: 'lifeCycle', initialState, diff --git a/src/slices/workflowSlice.ts b/src/slices/workflowSlice.ts index e6a9db5b46..a0c8a688b5 100644 --- a/src/slices/workflowSlice.ts +++ b/src/slices/workflowSlice.ts @@ -15,7 +15,7 @@ export type FieldSetField = { [key: string]: unknown } -type ConfigurationPanelField = { +export type ConfigurationPanelField = { // We could potentially specify 'fieldset' more, but I cannot find a definition // for which key value pairs are allowed fieldset?: FieldSetField[] // Values can be anything diff --git a/src/styles/main.scss b/src/styles/main.scss index 93ec2056a1..1175d45b6f 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -626,3 +626,8 @@ tr.info { overflow: hidden; text-overflow: ellipsis; } + +// React-JS-Cron +.my-project-cron-select-dropdown { + z-index: 10000; +} \ No newline at end of file diff --git a/src/utils/componentStyles.ts b/src/utils/componentStyles.ts index 599d0c68e6..8bee3a5c71 100644 --- a/src/utils/componentStyles.ts +++ b/src/utils/componentStyles.ts @@ -19,6 +19,8 @@ export function dropDownStyle(type: DropDownType): StylesConfig { ? 360 : type === "aclTemplate" || type === "comment" || type === "filter" ? 200 + : type === "policyAction" + ? 150 : 250; return { diff --git a/src/utils/dropDownUtils.ts b/src/utils/dropDownUtils.ts index c3c1b052e7..b80e040379 100644 --- a/src/utils/dropDownUtils.ts +++ b/src/utils/dropDownUtils.ts @@ -31,6 +31,10 @@ export const filterBySearch = (filterText: string, type: DropDownType, options: return options.filter((item) => t(item.label).toLowerCase().includes(filterText) ); + } else if (type === "policyAction") { + return options.filter((item) => + t(item).toLowerCase().includes(filterText) + ); } else { return options.filter((item) => item.value.toLowerCase().includes(filterText) @@ -127,7 +131,14 @@ export const formatDropDownOptions = ( label: item.label, }); } - } else { + } else if (type === "policyAction") { + for (const item of unformattedOptions) { + formattedOptions.push({ + value: item, + label: item, + }); + } + }else { for (const item of unformattedOptions) { formattedOptions.push({ value: item.value, diff --git a/src/utils/lifeCycleUtils.ts b/src/utils/lifeCycleUtils.ts new file mode 100644 index 0000000000..f39117dde7 --- /dev/null +++ b/src/utils/lifeCycleUtils.ts @@ -0,0 +1,16 @@ +import { LifeCyclePolicy, TargetFilter } from "../slices/lifeCycleSlice"; + +export const parseTargetFiltersForSubmit = ( + targetFiltersArray: (TargetFilter & { filter: string })[] +) => { + const targetFilters: LifeCyclePolicy["targetFilters"] = {} + for (const filter of targetFiltersArray) { + targetFilters[filter.filter] = { + value: filter.value, + type: filter.type, + must: filter.must + } + } + + return targetFilters; +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 8e6857d36b..a5e0948c82 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -165,3 +165,13 @@ export const translateOverrideFallback = (asset: UploadAssetOption, t: TFunction return result; } + +/** + * (Hopefully) Typesafe way of checking if an object has a specific property + */ +export function hasOwnProperty( + obj: O, + key: K, +): obj is O & Record { + return Object.prototype.hasOwnProperty.call(obj, key); +} diff --git a/src/utils/validate.ts b/src/utils/validate.ts index 7d1829bdea..0cc0eb2346 100644 --- a/src/utils/validate.ts +++ b/src/utils/validate.ts @@ -225,3 +225,30 @@ export const EditGroupSchema = Yup.object().shape({ export const AdopterRegistrationSchema = Yup.object().shape({ email: Yup.string().email(), }); + +// Validation Schema used in lifecycle policy modal +export const LifeCyclePolicySchema = [ + Yup.object().shape({ + title: Yup.string().required("Required"), + isActive: Yup.bool().required("Required"), + targetType: Yup.string().required("Required"), + timing: Yup.string().required("Required"), + action: Yup.string().required("Required"), + actionParameters: Yup.object().shape({ + // Property only required if it actually exists on the object + workflowId: Yup.string().required("Required"), + // workflowId: Yup.string().when("workflowId", { + // is: (exists: any) => !!exists, + // then: Yup.string().required("Required"), + // }), + }), + actionDate: Yup.date().when("timing", { + is: (timing: string) => timing === "SPECIFIC_DATE", + then: () => Yup.date().required("Required"), + }), + cronTrigger: Yup.string().when("timing", { + is: (timing: string) => timing === "REPEATING", + then: () => Yup.string().required("Required"), + }), + }), +];