1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-21 14:50:08 +03:00

M #~: Add sockets to listen global events (#1280)

This commit is contained in:
Sergio Betanzos 2021-06-07 13:27:38 +02:00 committed by GitHub
parent 9ebce37139
commit 6cbdfd2631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 1227 additions and 1022 deletions

View File

@ -49,7 +49,7 @@
"http": "0.0.1-security",
"http-proxy-middleware": "1.0.5",
"https": "1.0.0",
"iconoir-react": "^1.1.0",
"iconoir-react": "1.1.0",
"immutable": "4.0.0-rc.12",
"intersection-observer": "0.11.0",
"jsonschema": "1.2.7",
@ -59,7 +59,7 @@
"luxon": "1.25.0",
"marked": "2.0.0",
"morgan": "1.10.0",
"notistack": "1.0.1",
"notistack": "1.0.9",
"opennebula-guacamole": "1.0.0",
"path": "0.12.7",
"prop-types": "15.7.2",
@ -1675,11 +1675,11 @@
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
"integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dependencies": {
"@nodelib/fs.stat": "2.0.4",
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
},
"engines": {
@ -1687,19 +1687,19 @@
}
},
"node_modules/@nodelib/fs.stat": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"engines": {
"node": ">= 8"
}
},
"node_modules/@nodelib/fs.walk": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
"integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz",
"integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==",
"dependencies": {
"@nodelib/fs.scandir": "2.1.4",
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
},
"engines": {
@ -1780,9 +1780,9 @@
"integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q=="
},
"node_modules/@types/node": {
"version": "15.6.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
"integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA=="
"version": "15.12.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.1.tgz",
"integrity": "sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw=="
},
"node_modules/@types/prop-types": {
"version": "15.7.3",
@ -1790,9 +1790,9 @@
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
},
"node_modules/@types/react": {
"version": "17.0.8",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.8.tgz",
"integrity": "sha512-3sx4c0PbXujrYAKwXxNONXUtRp9C+hE2di0IuxFyf5BELD+B+AXL8G7QrmSKhVwKZDbv0igiAjQAMhXj8Yg3aw==",
"version": "17.0.9",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.9.tgz",
"integrity": "sha512-2Cw7FvevpJxQrCb+k5t6GH1KIvmadj5uBbjPaLlJB/nZWUj56e1ZqcD6zsoMFB47MsJUTFl9RJ132A7hb3QFJA==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@ -2956,9 +2956,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001232",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001232.tgz",
"integrity": "sha512-e4Gyp7P8vqC2qV2iHA+cJNf/yqUKOShXQOJHQt81OHxlIZl/j/j3soEA0adAQi8CPUQgvOdDENyQ5kd6a6mNSg==",
"version": "1.0.30001234",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz",
"integrity": "sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
@ -3662,9 +3662,9 @@
}
},
"node_modules/core-js": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.13.1.tgz",
"integrity": "sha512-JqveUc4igkqwStL2RTRn/EPFGBOfEZHxJl/8ej1mXJR75V3go2mFF4bmUYkEIT1rveHKnkUlcJX/c+f1TyIovQ==",
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.14.0.tgz",
"integrity": "sha512-3s+ed8er9ahK+zJpp9ZtuVcDoFzHNiZsPbNAAE4KXgrRHbjSqqNN6xGSXq6bq7TZIbKj4NLrLb6bJ5i+vSVjHA==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
@ -3672,9 +3672,9 @@
}
},
"node_modules/core-js-compat": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.13.1.tgz",
"integrity": "sha512-mdrcxc0WznfRd8ZicEZh1qVeJ2mu6bwQFh8YVUK48friy/FOwFV5EJj9/dlh+nMQ74YusdVfBFDuomKgUspxWQ==",
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz",
"integrity": "sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==",
"dependencies": {
"browserslist": "^4.16.6",
"semver": "7.0.0"
@ -4158,9 +4158,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"node_modules/electron-to-chromium": {
"version": "1.3.743",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.743.tgz",
"integrity": "sha512-K2wXfo9iZQzNJNx67+Pld0DRF+9bYinj62gXCdgPhcu1vidwVuLPHQPPFnCdO55njWigXXpfBiT90jGUPbw8Zg=="
"version": "1.3.749",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz",
"integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A=="
},
"node_modules/elliptic": {
"version": "6.5.4",
@ -6304,7 +6304,8 @@
"node_modules/https": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
"integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q="
"integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q=",
"license": "ISC"
},
"node_modules/https-browserify": {
"version": "1.0.0",
@ -6320,6 +6321,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/iconoir-react/-/iconoir-react-1.1.0.tgz",
"integrity": "sha512-eVlXhKtRJOHsqqNNazM8j5eAZxPaISSrNoN4VnqwWzZw5SnLvHi5Qp2kuKKznnx2vEIv4zcB4iqBQmmRW0vJ0A==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.7.2"
},
@ -7441,24 +7443,16 @@
}
},
"node_modules/mime-types": {
"version": "2.1.30",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
"integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
"version": "2.1.31",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
"dependencies": {
"mime-db": "1.47.0"
"mime-db": "1.48.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types/node_modules/mime-db": {
"version": "1.47.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
"integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mimic-response": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
@ -7865,9 +7859,9 @@
}
},
"node_modules/notistack": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.1.tgz",
"integrity": "sha512-2T1WkokzRCM8N9EdueaXja160IMFIMHVhRu0fGkDje7qCzwBHlTMZY2NULQzB2GFOO6iGVzl5GCX2XrJIzI8bw==",
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.9.tgz",
"integrity": "sha512-Dal2HtTpWrdYCZ3t0HhJt47NJZwVSPee36WzORRbqUkFR0k9pxFszxBuPSWshBLwF6Av8s86XPP+ED5zRz0CGw==",
"dependencies": {
"clsx": "^1.1.0",
"hoist-non-react-statics": "^3.3.0"
@ -7878,8 +7872,8 @@
},
"peerDependencies": {
"@material-ui/core": "^4.0.0",
"react": "^16.8.0",
"react-dom": "^16.8.0"
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0"
}
},
"node_modules/npmlog": {
@ -13203,25 +13197,25 @@
}
},
"@nodelib/fs.scandir": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
"integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"requires": {
"@nodelib/fs.stat": "2.0.4",
"@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9"
}
},
"@nodelib/fs.stat": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q=="
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="
},
"@nodelib/fs.walk": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
"integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz",
"integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==",
"requires": {
"@nodelib/fs.scandir": "2.1.4",
"@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0"
}
},
@ -13292,9 +13286,9 @@
"integrity": "sha512-bpcvu/MKHHeYX+qeEN8GE7DIravODWdACVA1ctevD8CN24RhPZIKMn9ntfAsrvLfSX3cR5RrBKAbYm9bGs0A+Q=="
},
"@types/node": {
"version": "15.6.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.6.1.tgz",
"integrity": "sha512-7EIraBEyRHEe7CH+Fm1XvgqU6uwZN8Q7jppJGcqjROMT29qhAuuOxYB1uEY5UMYQKEmA5D+5tBnhdaPXSsLONA=="
"version": "15.12.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.1.tgz",
"integrity": "sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw=="
},
"@types/prop-types": {
"version": "15.7.3",
@ -13302,9 +13296,9 @@
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
},
"@types/react": {
"version": "17.0.8",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.8.tgz",
"integrity": "sha512-3sx4c0PbXujrYAKwXxNONXUtRp9C+hE2di0IuxFyf5BELD+B+AXL8G7QrmSKhVwKZDbv0igiAjQAMhXj8Yg3aw==",
"version": "17.0.9",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.9.tgz",
"integrity": "sha512-2Cw7FvevpJxQrCb+k5t6GH1KIvmadj5uBbjPaLlJB/nZWUj56e1ZqcD6zsoMFB47MsJUTFl9RJ132A7hb3QFJA==",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@ -14262,9 +14256,9 @@
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"caniuse-lite": {
"version": "1.0.30001232",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001232.tgz",
"integrity": "sha512-e4Gyp7P8vqC2qV2iHA+cJNf/yqUKOShXQOJHQt81OHxlIZl/j/j3soEA0adAQi8CPUQgvOdDENyQ5kd6a6mNSg=="
"version": "1.0.30001234",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001234.tgz",
"integrity": "sha512-a3gjUVKkmwLdNysa1xkUAwN2VfJUJyVW47rsi3aCbkRCtbHAfo+rOsCqVw29G6coQ8gzAPb5XBXwiGHwme3isA=="
},
"chalk": {
"version": "2.4.2",
@ -14811,14 +14805,14 @@
}
},
"core-js": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.13.1.tgz",
"integrity": "sha512-JqveUc4igkqwStL2RTRn/EPFGBOfEZHxJl/8ej1mXJR75V3go2mFF4bmUYkEIT1rveHKnkUlcJX/c+f1TyIovQ=="
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.14.0.tgz",
"integrity": "sha512-3s+ed8er9ahK+zJpp9ZtuVcDoFzHNiZsPbNAAE4KXgrRHbjSqqNN6xGSXq6bq7TZIbKj4NLrLb6bJ5i+vSVjHA=="
},
"core-js-compat": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.13.1.tgz",
"integrity": "sha512-mdrcxc0WznfRd8ZicEZh1qVeJ2mu6bwQFh8YVUK48friy/FOwFV5EJj9/dlh+nMQ74YusdVfBFDuomKgUspxWQ==",
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz",
"integrity": "sha512-R4NS2eupxtiJU+VwgkF9WTpnSfZW4pogwKHd8bclWU2sp93Pr5S1uYJI84cMOubJRou7bcfL0vmwtLslWN5p3A==",
"requires": {
"browserslist": "^4.16.6",
"semver": "7.0.0"
@ -15230,9 +15224,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"electron-to-chromium": {
"version": "1.3.743",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.743.tgz",
"integrity": "sha512-K2wXfo9iZQzNJNx67+Pld0DRF+9bYinj62gXCdgPhcu1vidwVuLPHQPPFnCdO55njWigXXpfBiT90jGUPbw8Zg=="
"version": "1.3.749",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz",
"integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A=="
},
"elliptic": {
"version": "6.5.4",
@ -17775,18 +17769,11 @@
"integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ=="
},
"mime-types": {
"version": "2.1.30",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz",
"integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==",
"version": "2.1.31",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz",
"integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==",
"requires": {
"mime-db": "1.47.0"
},
"dependencies": {
"mime-db": {
"version": "1.47.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz",
"integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw=="
}
"mime-db": "1.48.0"
}
},
"mimic-response": {
@ -18136,9 +18123,9 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
"notistack": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.1.tgz",
"integrity": "sha512-2T1WkokzRCM8N9EdueaXja160IMFIMHVhRu0fGkDje7qCzwBHlTMZY2NULQzB2GFOO6iGVzl5GCX2XrJIzI8bw==",
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.9.tgz",
"integrity": "sha512-Dal2HtTpWrdYCZ3t0HhJt47NJZwVSPee36WzORRbqUkFR0k9pxFszxBuPSWshBLwF6Av8s86XPP+ED5zRz0CGw==",
"requires": {
"clsx": "^1.1.0",
"hoist-non-react-statics": "^3.3.0"

View File

@ -93,7 +93,7 @@
"luxon": "1.25.0",
"marked": "2.0.0",
"morgan": "1.10.0",
"notistack": "1.0.1",
"notistack": "1.0.9",
"opennebula-guacamole": "1.0.0",
"path": "0.12.7",
"prop-types": "15.7.2",
@ -129,4 +129,4 @@
"yup": "0.32.9",
"zeromq": "5.2.0"
}
}
}

View File

@ -1,82 +0,0 @@
const CHANGE_ZONE = 'CHANGE_ZONE'
const CHANGE_LOADING = 'CHANGE_LOADING'
const TOGGLE_MENU = 'TOGGLE_MENU'
const FIX_MENU = 'FIX_MENU'
const ENQUEUE_SNACKBAR = 'ENQUEUE_SNACKBAR'
const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR'
const REMOVE_SNACKBAR = 'REMOVE_SNACKBAR'
const Actions = {
CHANGE_ZONE,
CHANGE_LOADING,
TOGGLE_MENU,
FIX_MENU,
ENQUEUE_SNACKBAR,
CLOSE_SNACKBAR,
REMOVE_SNACKBAR
}
module.exports = {
Actions,
changeZone: zone => ({
type: CHANGE_ZONE,
payload: { zone }
}),
changeLoading: isLoading => ({
type: CHANGE_LOADING,
payload: { isLoading }
}),
openMenu: isOpen => ({
type: TOGGLE_MENU,
isOpen
}),
fixMenu: isFixed => ({
type: FIX_MENU,
isFixed
}),
enqueueSnackbar: notification => {
const key = notification.options && notification.options.key
return {
type: ENQUEUE_SNACKBAR,
notification: {
...notification,
key: key || new Date().getTime() + Math.random()
}
}
},
enqueueError: message => ({
type: ENQUEUE_SNACKBAR,
notification: {
key: new Date().getTime() + Math.random(),
message,
options: { variant: 'error' }
}
}),
enqueueSuccess: message => ({
type: ENQUEUE_SNACKBAR,
notification: {
key: new Date().getTime() + Math.random(),
message,
options: { variant: 'success' }
}
}),
enqueueInfo: message => ({
type: ENQUEUE_SNACKBAR,
notification: {
key: new Date().getTime() + Math.random(),
message,
options: { variant: 'info' }
}
}),
closeSnackbar: key => ({
type: CLOSE_SNACKBAR,
dismissAll: !key, // dismiss all if no key has been defined
key
}),
removeSnackbar: key => ({
type: REMOVE_SNACKBAR,
key
})
}

View File

@ -1,139 +0,0 @@
const START_ONE_REQUEST = 'START_ONE_REQUEST'
const SUCCESS_ONE_REQUEST = 'SUCCESS_ONE_REQUEST'
const FAILURE_ONE_REQUEST = 'FAILURE_ONE_REQUEST'
const Actions = {
START_ONE_REQUEST,
SUCCESS_ONE_REQUEST,
FAILURE_ONE_REQUEST
}
module.exports = {
Actions,
// --------------------------------------------
// ONE
// --------------------------------------------
setVms: vms => ({
type: SUCCESS_ONE_REQUEST,
payload: { vms }
}),
setTemplates: templates => ({
type: SUCCESS_ONE_REQUEST,
payload: { templates }
}),
setDatastores: datastores => ({
type: SUCCESS_ONE_REQUEST,
payload: { datastores }
}),
setVRouters: virtualRouters => ({
type: SUCCESS_ONE_REQUEST,
payload: { virtualRouters }
}),
setVmGroups: vmGroups => ({
type: SUCCESS_ONE_REQUEST,
payload: { vmGroups }
}),
setImages: images => ({
type: SUCCESS_ONE_REQUEST,
payload: { images }
}),
setFiles: files => ({
type: SUCCESS_ONE_REQUEST,
payload: { files }
}),
setMarketplaces: marketplaces => ({
type: SUCCESS_ONE_REQUEST,
payload: { marketplaces }
}),
setApps: apps => ({
type: SUCCESS_ONE_REQUEST,
payload: { apps }
}),
setVNetworks: vNetworks => ({
type: SUCCESS_ONE_REQUEST,
payload: { vNetworks }
}),
setVNetworksTemplates: vNetworksTemplates => ({
type: SUCCESS_ONE_REQUEST,
payload: { vNetworksTemplates }
}),
setSecGroups: securityGroups => ({
type: SUCCESS_ONE_REQUEST,
payload: { securityGroups }
}),
setClusters: clusters => ({
type: SUCCESS_ONE_REQUEST,
payload: { clusters }
}),
setHosts: hosts => ({
type: SUCCESS_ONE_REQUEST,
payload: { hosts }
}),
setZones: zones => ({
type: SUCCESS_ONE_REQUEST,
payload: { zones }
}),
setUsers: users => ({
type: SUCCESS_ONE_REQUEST,
payload: { users }
}),
setGroups: groups => ({
type: SUCCESS_ONE_REQUEST,
payload: { groups }
}),
setVdc: vdc => ({
type: SUCCESS_ONE_REQUEST,
payload: { vdc }
}),
setAcl: acl => ({
type: SUCCESS_ONE_REQUEST,
payload: { acl }
}),
// --------------------------------------------
// ONE FLOW
// --------------------------------------------
setApplications: applications => ({
type: SUCCESS_ONE_REQUEST,
payload: { applications }
}),
setApplicationsTemplates: applicationsTemplates => ({
type: SUCCESS_ONE_REQUEST,
payload: { applicationsTemplates }
}),
// --------------------------------------------
// ONE PROVISION
// --------------------------------------------
setProvisionsTemplates: provisionsTemplates => ({
type: SUCCESS_ONE_REQUEST,
payload: { provisionsTemplates }
}),
setProviders: providers => ({
type: SUCCESS_ONE_REQUEST,
payload: { providers }
}),
setProvisions: provisions => ({
type: SUCCESS_ONE_REQUEST,
payload: { provisions }
}),
// --------------------------------------------
// ONE REQUEST
// --------------------------------------------
startOneRequest: () => ({
type: START_ONE_REQUEST
}),
successOneRequest: () => ({
type: SUCCESS_ONE_REQUEST
}),
failureOneRequest: error => ({
type: FAILURE_ONE_REQUEST,
payload: { error }
})
}

View File

@ -1,54 +0,0 @@
const START_AUTH = 'START_AUTH'
const SELECT_FILTER_GROUP = 'SELECT_FILTER_GROUP'
const CHANGE_SETTINGS = 'CHANGE_SETTINGS'
const SUCCESS_AUTH = 'SUCCESS_AUTH'
const FAILURE_AUTH = 'FAILURE_AUTH'
const LOGOUT = 'LOGOUT'
const Actions = {
START_AUTH,
SELECT_FILTER_GROUP,
CHANGE_SETTINGS,
SUCCESS_AUTH,
FAILURE_AUTH,
LOGOUT
}
module.exports = {
Actions,
startAuth: () => ({
type: START_AUTH
}),
updateSetting: (dispatch, getState) => {
const current = getState()
const userSetting = current.Authenticated?.user?.TEMPLATE?.FIREEDGE
if (!userSetting) return
const mapSetting = Object.entries(userSetting)
.reduce((res, [key, value]) =>
({ ...res, [String(key).toLowerCase()]: value })
, {})
dispatch(({
type: CHANGE_SETTINGS,
payload: mapSetting
}))
},
selectFilterGroup: payload => ({
type: SELECT_FILTER_GROUP,
payload
}),
successAuth: payload => ({
type: SUCCESS_AUTH,
payload
}),
failureAuth: payload => ({
type: FAILURE_AUTH,
payload
}),
logout: () => ({
type: LOGOUT
})
}

View File

@ -6,8 +6,8 @@ import { Db as ProviderIcon, Cloud as ProvisionIcon } from 'iconoir-react'
import SelectCard, { Action } from 'client/components/Cards/SelectCard'
import { StatusBadge } from 'client/components/Status'
import Image from 'client/components/Image'
import { isExternalURL } from 'client/utils'
import * as Types from 'client/types/provision'
import {
PROVISIONS_STATES,
PROVIDER_IMAGES_URL,
@ -65,10 +65,7 @@ const ProvisionCard = memo(
)
ProvisionCard.propTypes = {
value: PropTypes.oneOfType([
Types.Provider,
Types.Provision
]),
value: PropTypes.object,
isSelected: PropTypes.bool,
handleClick: PropTypes.func,
isProvider: PropTypes.bool,

View File

@ -3,9 +3,7 @@ import PropTypes from 'prop-types'
import { Db as ProviderIcon, SettingsCloud as ProvisionIcon } from 'iconoir-react'
import * as Types from 'client/types/provision'
import { SelectCard } from 'client/components/Cards'
import Image from 'client/components/Image'
import { isExternalURL } from 'client/utils'
import { PROVIDER_IMAGES_URL, PROVISION_IMAGES_URL } from 'client/constants'
@ -49,10 +47,7 @@ ProvisionTemplateCard.propTypes = {
isProvider: PropTypes.bool,
isSelected: PropTypes.bool,
isValid: PropTypes.bool,
value: PropTypes.oneOfType([
Types.ProviderTemplate,
Types.ProvisionTemplate
])
value: PropTypes.object
}
ProvisionTemplateCard.defaultProps = {

View File

@ -0,0 +1,60 @@
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import { ViewGrid as VmIcon } from 'iconoir-react'
import SelectCard, { Action } from 'client/components/Cards/SelectCard'
import { StatusBadge } from 'client/components/Status'
import { getState } from 'client/models/VirtualMachine'
const VirtualMachineCard = memo(
({ value, isSelected, handleClick, actions }) => {
const { ID, NAME } = value
const { color, name } = getState(value) ?? {}
return (
<SelectCard
action={actions?.map(action =>
<Action key={action?.cy} {...action} />
)}
dataCy={`vm-${ID}`}
handleClick={handleClick}
icon={(
<StatusBadge title={name} stateColor={color}>
<VmIcon />
</StatusBadge>
)}
isSelected={isSelected}
subheader={`#${ID}`}
title={NAME}
/>
)
},
(prev, next) =>
prev.isSelected === next.isSelected &&
prev.value.STATE === next.value.STATE &&
prev.value?.LCM_STATE === next.value?.LCM_STATE
)
VirtualMachineCard.propTypes = {
handleClick: PropTypes.func,
isSelected: PropTypes.bool,
value: PropTypes.object,
actions: PropTypes.arrayOf(
PropTypes.shape({
handleClick: PropTypes.func.isRequired,
icon: PropTypes.object.isRequired,
cy: PropTypes.string
})
)
}
VirtualMachineCard.defaultProps = {
handleClick: undefined,
isSelected: false,
value: {},
actions: undefined
}
VirtualMachineCard.displayName = 'VirtualMachineCard'
export default VirtualMachineCard

View File

@ -11,6 +11,7 @@ import ProvisionCard from 'client/components/Cards/ProvisionCard'
import ProvisionTemplateCard from 'client/components/Cards/ProvisionTemplateCard'
import SelectCard from 'client/components/Cards/SelectCard'
import TierCard from 'client/components/Cards/TierCard'
import VirtualMachineCard from 'client/components/Cards/VirtualMachineCard'
import WavesCard from 'client/components/Cards/WavesCard'
export {
@ -27,5 +28,6 @@ export {
ProvisionTemplateCard,
SelectCard,
TierCard,
VirtualMachineCard,
WavesCard
}

View File

@ -44,11 +44,13 @@ const DebugLog = memo(({ uuid, socket, logDefault, title }) => {
}))
useEffect(() => {
uuid && socket?.on((socketData = {}) => {
const { on, off } = socket((socketData = {}) => {
socketData.id === uuid &&
setLog(prevLog => LogUtils.concatNewMessageToLog(prevLog, socketData))
})
return () => uuid && socket?.off()
uuid && on()
return off
}, [])
return (
@ -68,10 +70,7 @@ const DebugLog = memo(({ uuid, socket, logDefault, title }) => {
DebugLog.propTypes = {
uuid: PropTypes.string,
socket: PropTypes.shape({
on: PropTypes.func.isRequired,
off: PropTypes.func.isRequired
}).isRequired,
socket: PropTypes.func.isRequired,
logDefault: PropTypes.object,
title: PropTypes.oneOfType([
PropTypes.element,

View File

@ -12,7 +12,7 @@ import {
} from '@material-ui/core'
import { NavArrowRight as CollapseIcon, NavArrowDown as ExpandMoreIcon } from 'iconoir-react'
import { useGeneral } from 'client/hooks'
import { useGeneral } from 'client/features/General'
import SidebarLink from 'client/components/Sidebar/SidebarLink'
import sidebarStyles from 'client/components/Sidebar/styles'

View File

@ -21,7 +21,7 @@ export default {
light: '#3adb76',
main: '#4caf50',
dark: '#388e3c',
contrastText: 'rgba(0, 0, 0, 0.87)'
contrastText: '#fff'
},
debug: {
light: '#7f7f7f',

View File

@ -72,7 +72,13 @@ export const DEBUG_LEVEL = {
DEBUG: 'DEBUG'
}
export const SOCKETS = {
hooks: 'hooks',
provision: 'provision'
}
export * as T from 'client/constants/translates'
export * as STATES from 'client/constants/states'
export * from 'client/constants/flow'
export * from 'client/constants/states'
export * from 'client/constants/provision'
export * from 'client/constants/vm'

View File

@ -1,26 +1,100 @@
export const PENDING = 'PENDING'
export const DEPLOYING = 'DEPLOYING'
export const RUNNING = 'RUNNING'
export const UNDEPLOYING = 'UNDEPLOYING'
export const WARNING = 'WARNING'
export const DONE = 'DONE'
export const FAILED_UNDEPLOYING = 'FAILED_UNDEPLOYING'
export const FAILED_DEPLOYING = 'FAILED_DEPLOYING'
export const SCALING = 'SCALING'
export const FAILED_SCALING = 'FAILED_SCALING'
export const ACTIVE = 'ACTIVE'
export const BOOT = 'BOOT'
export const BOOT_FAILURE = 'BOOT_FAILURE'
export const BOOT_MIGRATE = 'BOOT_MIGRATE'
export const BOOT_MIGRATE_FAILURE = 'BOOT_MIGRATE_FAILURE'
export const BOOT_POWEROFF = 'BOOT_POWEROFF'
export const BOOT_STOPPED = 'BOOT_STOPPED'
export const BOOT_STOPPED_FAILURE = 'BOOT_STOPPED_FAILURE'
export const BOOT_SUSPENDED = 'BOOT_SUSPENDED'
export const BOOT_UNDEPLOY = 'BOOT_UNDEPLOY'
export const BOOT_UNDEPLOY_FAILURE = 'BOOT_UNDEPLOY_FAILURE'
export const BOOT_UNKNOWN = 'BOOT_UNKNOWN'
export const CANCEL = 'CANCEL'
export const CLEANUP_DELETE = 'CLEANUP_DELETE'
export const CLEANUP_RESUBMIT = 'CLEANUP_RESUBMIT'
export const CLONING = 'CLONING'
export const CLONING_FAILURE = 'CLONING_FAILURE'
export const CONFIGURING = 'CONFIGURING'
export const COOLDOWN = 'COOLDOWN'
export const DELETING = 'DELETING'
export const DEPLOYING = 'DEPLOYING'
export const DISABLED = 'DISABLED'
export const DISK_RESIZE = 'DISK_RESIZE'
export const DISK_RESIZE_POWEROFF = 'DISK_RESIZE_POWEROFF'
export const DISK_RESIZE_UNDEPLOYED = 'DISK_RESIZE_UNDEPLOYED'
export const DISK_SNAPSHOT = 'DISK_SNAPSHOT'
export const DISK_SNAPSHOT_DELETE = 'DISK_SNAPSHOT_DELETE'
export const DISK_SNAPSHOT_DELETE_POWEROFF = 'DISK_SNAPSHOT_DELETE_POWEROFF'
export const DISK_SNAPSHOT_DELETE_SUSPENDED = 'DISK_SNAPSHOT_DELETE_SUSPENDED'
export const DISK_SNAPSHOT_POWEROFF = 'DISK_SNAPSHOT_POWEROFF'
export const DISK_SNAPSHOT_REVERT = 'DISK_SNAPSHOT_REVERT'
export const DISK_SNAPSHOT_REVERT_POWEROFF = 'DISK_SNAPSHOT_REVERT_POWEROFF'
export const DISK_SNAPSHOT_REVERT_SUSPENDED = 'DISK_SNAPSHOT_REVERT_SUSPENDED'
export const DISK_SNAPSHOT_SUSPENDED = 'DISK_SNAPSHOT_SUSPENDED'
export const DONE = 'DONE'
export const EPILOG = 'EPILOG'
export const EPILOG_FAILURE = 'EPILOG_FAILURE'
export const EPILOG_STOP = 'EPILOG_STOP'
export const EPILOG_STOP_FAILURE = 'EPILOG_STOP_FAILURE'
export const EPILOG_UNDEPLOY = 'EPILOG_UNDEPLOY'
export const EPILOG_UNDEPLOY_FAILURE = 'EPILOG_UNDEPLOY_FAILURE'
export const ERROR = 'ERROR'
export const FAILED = 'FAILED'
export const FAILED_DEPLOYING = 'FAILED_DEPLOYING'
export const FAILED_SCALING = 'FAILED_SCALING'
export const FAILED_UNDEPLOYING = 'FAILED_UNDEPLOYING'
export const FAILURE = 'FAILURE'
export const HOLD = 'HOLD'
export const HOTPLUG = 'HOTPLUG'
export const HOTPLUG_EPILOG_POWEROFF = 'HOTPLUG_EPILOG_POWEROFF'
export const HOTPLUG_NIC = 'HOTPLUG_NIC'
export const HOTPLUG_NIC_POWEROFF = 'HOTPLUG_NIC_POWEROFF'
export const HOTPLUG_PROLOG_POWEROFF = 'HOTPLUG_PROLOG_POWEROFF'
export const HOTPLUG_RESIZE = 'HOTPLUG_RESIZE'
export const HOTPLUG_SAVEAS = 'HOTPLUG_SAVEAS'
export const HOTPLUG_SAVEAS_POWEROFF = 'HOTPLUG_SAVEAS_POWEROFF'
export const HOTPLUG_SAVEAS_STOPPED = 'HOTPLUG_SAVEAS_STOPPED'
export const HOTPLUG_SAVEAS_SUSPENDED = 'HOTPLUG_SAVEAS_SUSPENDED'
export const HOTPLUG_SAVEAS_UNDEPLOYED = 'HOTPLUG_SAVEAS_UNDEPLOYED'
export const HOTPLUG_SNAPSHOT = 'HOTPLUG_SNAPSHOT'
export const INIT = 'INIT'
export const OFFLINE = 'OFFLINE'
export const LCM_INIT = 'LCM_INIT'
export const MIGRATE = 'MIGRATE'
export const MONITORED = 'MONITORED'
export const MONITORING_MONITORED = 'MONITORING_MONITORED'
export const MONITORING_DISABLED = 'MONITORING_DISABLED'
export const MONITORING_ERROR = 'MONITORING_ERROR'
export const MONITORING_INIT = 'MONITORING_INIT'
export const MONITORING_DISABLED = 'MONITORING_DISABLED'
export const MONITORING_MONITORED = 'MONITORING_MONITORED'
export const OFFLINE = 'OFFLINE'
export const PENDING = 'PENDING'
export const POWEROFF = 'POWEROFF'
export const PROLOG = 'PROLOG'
export const PROLOG_FAILURE = 'PROLOG_FAILURE'
export const PROLOG_MIGRATE = 'PROLOG_MIGRATE'
export const PROLOG_MIGRATE_FAILURE = 'PROLOG_MIGRATE_FAILURE'
export const PROLOG_MIGRATE_POWEROFF = 'PROLOG_MIGRATE_POWEROFF'
export const PROLOG_MIGRATE_POWEROFF_FAILURE = 'PROLOG_MIGRATE_POWEROFF_FAILURE'
export const PROLOG_MIGRATE_SUSPEND = 'PROLOG_MIGRATE_SUSPEND'
export const PROLOG_MIGRATE_SUSPEND_FAILURE = 'PROLOG_MIGRATE_SUSPEND_FAILURE'
export const PROLOG_MIGRATE_UNKNOWN = 'PROLOG_MIGRATE_UNKNOWN'
export const PROLOG_MIGRATE_UNKNOWN_FAILURE = 'PROLOG_MIGRATE_UNKNOWN_FAILURE'
export const PROLOG_RESUME = 'PROLOG_RESUME'
export const PROLOG_RESUME_FAILURE = 'PROLOG_RESUME_FAILURE'
export const PROLOG_UNDEPLOY = 'PROLOG_UNDEPLOY'
export const PROLOG_UNDEPLOY_FAILURE = 'PROLOG_UNDEPLOY_FAILURE'
export const READY = 'READY'
export const DISABLED = 'DISABLED'
export const CONFIGURING = 'CONFIGURING'
export const ERROR = 'ERROR'
export const DELETING = 'DELETING'
export const RUNNING = 'RUNNING'
export const SAVE_MIGRATE = 'SAVE_MIGRATE'
export const SAVE_STOP = 'SAVE_STOP'
export const SAVE_SUSPEND = 'SAVE_SUSPEND'
export const SCALING = 'SCALING'
export const SHUTDOWN = 'SHUTDOWN'
export const SHUTDOWN_POWEROFF = 'SHUTDOWN_POWEROFF'
export const SHUTDOWN_UNDEPLOY = 'SHUTDOWN_UNDEPLOY'
export const STOPPED = 'STOPPED'
export const SUSPENDED = 'SUSPENDED'
export const UNKNOWN = 'UNKNOWN'
export const UNDEPLOYED = 'UNDEPLOYED'
export const UNDEPLOYING = 'UNDEPLOYING'
export const WARNING = 'WARNING'

View File

@ -0,0 +1,413 @@
import * as STATES from 'client/constants/states'
import COLOR from 'client/constants/color'
export const VM_STATES = [
{ // 0
name: STATES.INIT,
color: COLOR.info.main,
meaning: ''
},
{ // 1
name: STATES.PENDING,
color: COLOR.info.main,
meaning: ''
},
{ // 2
name: STATES.HOLD,
color: COLOR.info.main,
meaning: ''
},
{ // 3
name: STATES.ACTIVE,
color: COLOR.info.main,
meaning: ''
},
{ // 4
name: STATES.STOPPED,
color: COLOR.info.main,
meaning: ''
},
{ // 5
name: STATES.SUSPENDED,
color: COLOR.info.main,
meaning: ''
},
{ // 6
name: STATES.DONE,
color: COLOR.debug.main,
meaning: ''
},
{ // 7
name: STATES.FAILED,
color: COLOR.info.main,
meaning: ''
},
{ // 8
name: STATES.POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 9
name: STATES.UNDEPLOYED,
color: COLOR.info.main,
meaning: ''
},
{ // 10
name: STATES.CLONING,
color: COLOR.info.main,
meaning: ''
},
{ // 11
name: STATES.CLONING_FAILURE,
color: COLOR.info.main,
meaning: ''
}
]
export const VM_LCM_STATES = [
{ // 0
name: STATES.LCM_INIT,
color: COLOR.info.main,
meaning: ''
},
{ // 1
name: STATES.PROLOG,
color: COLOR.info.main,
meaning: ''
},
{ // 2
name: STATES.BOOT,
color: COLOR.info.main,
meaning: ''
},
{ // 3
name: STATES.RUNNING,
color: COLOR.success.main,
meaning: ''
},
{ // 4
name: STATES.MIGRATE,
color: COLOR.info.main,
meaning: ''
},
{ // 5
name: STATES.SAVE_STOP,
color: COLOR.info.main,
meaning: ''
},
{ // 6
name: STATES.SAVE_SUSPEND,
color: COLOR.info.main,
meaning: ''
},
{ // 7
name: STATES.SAVE_MIGRATE,
color: COLOR.info.main,
meaning: ''
},
{ // 8
name: STATES.PROLOG_MIGRATE,
color: COLOR.info.main,
meaning: ''
},
{ // 9
name: STATES.PROLOG_RESUME,
color: COLOR.info.main,
meaning: ''
},
{ // 10
name: STATES.EPILOG_STOP,
color: COLOR.info.main,
meaning: ''
},
{ // 11
name: STATES.EPILOG,
color: COLOR.info.main,
meaning: ''
},
{ // 12
name: STATES.SHUTDOWN,
color: COLOR.info.main,
meaning: ''
},
{ // 13
name: STATES.CANCEL,
color: COLOR.info.main,
meaning: ''
},
{ // 14
name: STATES.FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 15
name: STATES.CLEANUP_RESUBMIT,
color: COLOR.info.main,
meaning: ''
},
{ // 16
name: STATES.UNKNOWN,
color: COLOR.info.main,
meaning: ''
},
{ // 17
name: STATES.HOTPLUG,
color: COLOR.info.main,
meaning: ''
},
{ // 18
name: STATES.SHUTDOWN_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 19
name: STATES.BOOT_UNKNOWN,
color: COLOR.info.main,
meaning: ''
},
{ // 20
name: STATES.BOOT_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 21
name: STATES.BOOT_SUSPENDED,
color: COLOR.info.main,
meaning: ''
},
{ // 22
name: STATES.BOOT_STOPPED,
color: COLOR.info.main,
meaning: ''
},
{ // 23
name: STATES.CLEANUP_DELETE,
color: COLOR.info.main,
meaning: ''
},
{ // 24
name: STATES.HOTPLUG_SNAPSHOT,
color: COLOR.info.main,
meaning: ''
},
{ // 25
name: STATES.HOTPLUG_NIC,
color: COLOR.info.main,
meaning: ''
},
{ // 26
name: STATES.HOTPLUG_SAVEAS,
color: COLOR.info.main,
meaning: ''
},
{ // 27
name: STATES.HOTPLUG_SAVEAS_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 28
name: STATES.HOTPLUG_SAVEAS_SUSPENDED,
color: COLOR.info.main,
meaning: ''
},
{ // 29
name: STATES.SHUTDOWN_UNDEPLOY,
color: COLOR.info.main,
meaning: ''
},
{ // 30
name: STATES.EPILOG_UNDEPLOY,
color: COLOR.info.main,
meaning: ''
},
{ // 31
name: STATES.PROLOG_UNDEPLOY,
color: COLOR.info.main,
meaning: ''
},
{ // 32
name: STATES.BOOT_UNDEPLOY,
color: COLOR.info.main,
meaning: ''
},
{ // 33
name: STATES.HOTPLUG_PROLOG_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 34
name: STATES.HOTPLUG_EPILOG_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 35
name: STATES.BOOT_MIGRATE,
color: COLOR.info.main,
meaning: ''
},
{ // 36
name: STATES.BOOT_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 37
name: STATES.BOOT_MIGRATE_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 38
name: STATES.PROLOG_MIGRATE_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 39
name: STATES.PROLOG_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 40
name: STATES.EPILOG_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 41
name: STATES.EPILOG_STOP_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 42
name: STATES.EPILOG_UNDEPLOY_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 43
name: STATES.PROLOG_MIGRATE_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 44
name: STATES.PROLOG_MIGRATE_POWEROFF_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 45
name: STATES.PROLOG_MIGRATE_SUSPEND,
color: COLOR.info.main,
meaning: ''
},
{ // 46
name: STATES.PROLOG_MIGRATE_SUSPEND_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 47
name: STATES.BOOT_UNDEPLOY_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 48
name: STATES.BOOT_STOPPED_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 49
name: STATES.PROLOG_RESUME_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 50
name: STATES.PROLOG_UNDEPLOY_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 51
name: STATES.DISK_SNAPSHOT_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 52
name: STATES.DISK_SNAPSHOT_REVERT_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 53
name: STATES.DISK_SNAPSHOT_DELETE_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 54
name: STATES.DISK_SNAPSHOT_SUSPENDED,
color: COLOR.info.main,
meaning: ''
},
{ // 55
name: STATES.DISK_SNAPSHOT_REVERT_SUSPENDED,
color: COLOR.info.main,
meaning: ''
},
{ // 56
name: STATES.DISK_SNAPSHOT_DELETE_SUSPENDED,
color: COLOR.info.main,
meaning: ''
},
{ // 57
name: STATES.DISK_SNAPSHOT,
color: COLOR.info.main,
meaning: ''
},
{ // 58
name: STATES.DISK_SNAPSHOT_REVERT,
color: COLOR.info.main,
meaning: ''
},
{ // 59
name: STATES.DISK_SNAPSHOT_DELETE,
color: COLOR.info.main,
meaning: ''
},
{ // 60
name: STATES.PROLOG_MIGRATE_UNKNOWN,
color: COLOR.info.main,
meaning: ''
},
{ // 61
name: STATES.PROLOG_MIGRATE_UNKNOWN_FAILURE,
color: COLOR.warning.main,
meaning: ''
},
{ // 62
name: STATES.DISK_RESIZE,
color: COLOR.info.main,
meaning: ''
},
{ // 63
name: STATES.DISK_RESIZE_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 64
name: STATES.DISK_RESIZE_UNDEPLOYED,
color: COLOR.info.main,
meaning: ''
},
{ // 65
name: STATES.HOTPLUG_NIC_POWEROFF,
color: COLOR.info.main,
meaning: ''
},
{ // 66
name: STATES.HOTPLUG_RESIZE,
color: COLOR.info.main,
meaning: ''
},
{ // 67
name: STATES.HOTPLUG_SAVEAS_UNDEPLOYED,
color: COLOR.info.main,
meaning: ''
},
{ // 68
name: STATES.HOTPLUG_SAVEAS_STOPPED,
color: COLOR.info.main,
meaning: ''
}
]

View File

@ -21,7 +21,7 @@ function ApplicationsTemplates () {
const { getApplicationsTemplates } = useApplicationTemplateApi()
const { error, fetchRequest, loading, reloading } = useFetch(getApplicationsTemplates)
console.log({ error })
useEffect(() => { fetchRequest() }, [])
return (

View File

@ -14,7 +14,6 @@ import { Action } from 'client/components/Cards/SelectCard'
import { Tr } from 'client/components/HOC'
import { T } from 'client/constants'
import * as Types from 'client/types/provision'
import useStyles from 'client/containers/Providers/Sections/styles'
const Info = memo(({ fetchProps }) => {
@ -153,7 +152,7 @@ const Info = memo(({ fetchProps }) => {
Info.propTypes = {
fetchProps: PropTypes.shape({
data: Types.Provision.isRequired
data: PropTypes.object.isRequired
}).isRequired
}

View File

@ -8,7 +8,6 @@ import { useDatastoreApi, useProvisionApi } from 'client/features/One'
import { useGeneralApi } from 'client/features/General'
import { ListCards } from 'client/components/List'
import { DatastoreCard } from 'client/components/Cards'
import * as Types from 'client/types/provision'
const Datastores = memo(
({ hidden, data, reloading, refetchProvision, disableAllActions }) => {
@ -54,7 +53,7 @@ const Datastores = memo(
)
Datastores.propTypes = {
data: Types.Provision.isRequired,
data: PropTypes.object.isRequired,
hidden: PropTypes.bool,
refetchProvision: PropTypes.func,
reloading: PropTypes.bool,

View File

@ -8,7 +8,6 @@ import { useHostApi, useProvisionApi } from 'client/features/One'
import { useGeneralApi } from 'client/features/General'
import { ListCards } from 'client/components/List'
import { HostCard } from 'client/components/Cards'
import * as Types from 'client/types/provision'
const Hosts = memo(
({ hidden, data, reloading, refetchProvision, disableAllActions }) => {
@ -62,7 +61,7 @@ const Hosts = memo(
prev.hidden === next.hidden && prev.reloading === next.reloading)
Hosts.propTypes = {
data: Types.Provision.isRequired,
data: PropTypes.object.isRequired,
hidden: PropTypes.bool,
refetchProvision: PropTypes.func,
reloading: PropTypes.bool,

View File

@ -16,8 +16,6 @@ import NetworksTab from 'client/containers/Provisions/DialogInfo/networks'
import HostsTab from 'client/containers/Provisions/DialogInfo/hosts'
import LogTab from 'client/containers/Provisions/DialogInfo/log'
import * as Types from 'client/types/provision'
const TABS = [
{ name: 'info', icon: InfoIcon, content: InfoTab },
{ name: 'datastores', icon: DatastoreIcon, content: DatastoresTab },
@ -78,7 +76,7 @@ const DialogInfo = ({ disableAllActions, fetchProps }) => {
DialogInfo.propTypes = {
disableAllActions: PropTypes.bool,
fetchProps: PropTypes.shape({
data: Types.Provision.isRequired,
data: PropTypes.object.isRequired,
fetchRequest: PropTypes.func,
reloading: PropTypes.bool
}).isRequired

View File

@ -1,4 +1,5 @@
import React, { memo } from 'react'
import PropTypes from 'prop-types'
import clsx from 'clsx'
import { List, ListItem, Typography, Grid, Paper, Divider } from '@material-ui/core'
@ -7,10 +8,9 @@ import { Check as CheckIcon, Square as BlankSquareIcon } from 'iconoir-react'
import useStyles from 'client/containers/Provisions/DialogInfo/styles'
import { StatusChip } from 'client/components/Status'
import { Tr } from 'client/components/HOC'
import * as Types from 'client/types/provision'
import { T, PROVISIONS_STATES } from 'client/constants'
const Info = memo(({ data }) => {
const Info = memo(({ data = {} }) => {
const classes = useStyles()
const { ID, GNAME, UNAME, PERMISSIONS, TEMPLATE } = data
const {
@ -124,11 +124,11 @@ const Info = memo(({ data }) => {
})
Info.propTypes = {
data: Types.Provision.isRequired
data: PropTypes.object.isRequired
}
Info.defaultProps = {
data: {}
data: undefined
}
Info.displayName = 'Info'

View File

@ -6,10 +6,9 @@ import { LinearProgress } from '@material-ui/core'
import { useFetch, useSocket } from 'client/hooks'
import { useProvisionApi } from 'client/features/One'
import DebugLog, { LogUtils } from 'client/components/DebugLog'
import * as Types from 'client/types/provision'
const Log = React.memo(({ hidden, data: { ID } }) => {
const { getProvision } = useSocket()
const { getProvisionSocket } = useSocket()
const { getProvisionLog } = useProvisionApi()
const {
@ -33,14 +32,14 @@ const Log = React.memo(({ hidden, data: { ID } }) => {
return loading ? (
<LinearProgress color='secondary' style={{ width: '100%' }} />
) : (
<DebugLog uuid={uuid} socket={getProvision} logDefault={parsedLog} />
<DebugLog uuid={uuid} socket={getProvisionSocket} logDefault={parsedLog} />
)
}, (prev, next) =>
prev.hidden === next.hidden && prev.reloading === next.reloading
)
Log.propTypes = {
data: Types.Provision.isRequired,
data: PropTypes.object.isRequired,
hidden: PropTypes.bool,
fetchRequest: PropTypes.func
}

View File

@ -8,7 +8,6 @@ import { useVNetworkApi, useProvisionApi } from 'client/features/One'
import { useGeneralApi } from 'client/features/General'
import { ListCards } from 'client/components/List'
import { NetworkCard } from 'client/components/Cards'
import * as Types from 'client/types/provision'
const Networks = memo(
({ hidden, data, reloading, refetchProvision, disableAllActions }) => {
@ -54,7 +53,7 @@ const Networks = memo(
)
Networks.propTypes = {
data: Types.Provision.isRequired,
data: PropTypes.object.isRequired,
hidden: PropTypes.bool,
refetchProvision: PropTypes.func,
reloading: PropTypes.bool,

View File

@ -27,7 +27,7 @@ function ProvisionCreateForm () {
const [uuid, setUuid] = useState(undefined)
const { getProvision } = useSocket()
const { getProvisionSocket } = useSocket()
const { getProviders } = useProviderApi()
const { createProvision } = useProvisionApi()
const { enqueueInfo } = useGeneralApi()
@ -80,7 +80,7 @@ function ProvisionCreateForm () {
return (
<DebugLog
uuid={uuid}
socket={getProvision}
socket={getProvisionSocket}
title={(
<div className={classes.titleWrapper}>
<IconButton aria-label='back-to-list' size='medium'

View File

@ -0,0 +1,159 @@
import React, { memo, useState } from 'react'
import PropTypes from 'prop-types'
import { List, ListItem, Typography, Grid, Paper, Divider } from '@material-ui/core'
import { CheckBox, CheckBoxOutlineBlank, Visibility } from '@material-ui/icons'
import clsx from 'clsx'
import { useProviderApi } from 'client/features/One'
import { Action } from 'client/components/Cards/SelectCard'
import { Tr } from 'client/components/HOC'
import { T } from 'client/constants'
import useStyles from 'client/containers/Providers/Sections/styles'
const Info = memo(({ data }) => {
const classes = useStyles()
const { getProviderConnection } = useProviderApi()
const [showConnection, setShowConnection] = useState(undefined)
const { ID, NAME, GNAME, UNAME, PERMISSIONS, TEMPLATE } = data
const {
connection,
description,
provider: providerName,
registration_time: time
} = TEMPLATE?.PROVISION_BODY
const hasConnection = connection && Object.keys(connection).length > 0
const isChecked = checked =>
checked === '1' ? <CheckBox /> : <CheckBoxOutlineBlank />
const ConnectionButton = () => (
<Action
icon={<Visibility />}
cy='provider-connection'
handleClick={() => getProviderConnection(ID).then(setShowConnection)}
/>
)
return (
<Grid container spacing={1}>
<Grid item xs={12} md={6}>
<Paper variant="outlined" className={classes.marginBottom}>
<List className={clsx(classes.list, 'w-50')}>
<ListItem className={classes.title}>
<Typography>{Tr(T.Information)}</Typography>
</ListItem>
<Divider />
<ListItem>
<Typography>{'ID'}</Typography>
<Typography>{ID}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Name)}</Typography>
<Typography data-cy="provider-name">{NAME}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Description)}</Typography>
<Typography data-cy="provider-description" noWrap>{description}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Provider)}</Typography>
<Typography data-cy="provider-type">{providerName}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.RegistrationTime)}</Typography>
<Typography>
{new Date(time * 1000).toLocaleString()}
</Typography>
</ListItem>
</List>
</Paper>
{hasConnection && (
<Paper variant="outlined">
<List className={clsx(classes.list, 'w-50')}>
<ListItem className={classes.title}>
<Typography>{Tr(T.Credentials)}</Typography>
<span className={classes.alignToRight}>
{!showConnection && <ConnectionButton />}
</span>
</ListItem>
<Divider />
{Object.entries(connection)?.map(([key, value]) =>
typeof value === 'string' && (
<ListItem key={key}>
<Typography>{key}</Typography>
<Typography data-cy={`provider-${key}`}>
{showConnection?.[key] ?? value}
</Typography>
</ListItem>
))}
</List>
</Paper>
)}
</Grid>
<Grid item xs={12} md={6}>
<Paper variant="outlined" className={classes.marginBottom}>
<List className={clsx(classes.list, 'w-25')}>
<ListItem className={classes.title}>
<Typography>{Tr(T.Permissions)}</Typography>
<Typography>{Tr(T.Use)}</Typography>
<Typography>{Tr(T.Manage)}</Typography>
<Typography>{Tr(T.Admin)}</Typography>
</ListItem>
<Divider />
<ListItem>
<Typography>{Tr(T.Owner)}</Typography>
<Typography>{isChecked(PERMISSIONS.OWNER_U)}</Typography>
<Typography>{isChecked(PERMISSIONS.OWNER_M)}</Typography>
<Typography>{isChecked(PERMISSIONS.OWNER_A)}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Group)}</Typography>
<Typography>{isChecked(PERMISSIONS.GROUP_U)}</Typography>
<Typography>{isChecked(PERMISSIONS.GROUP_M)}</Typography>
<Typography>{isChecked(PERMISSIONS.GROUP_A)}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Other)}</Typography>
<Typography>{isChecked(PERMISSIONS.OTHER_U)}</Typography>
<Typography>{isChecked(PERMISSIONS.OTHER_M)}</Typography>
<Typography>{isChecked(PERMISSIONS.OTHER_A)}</Typography>
</ListItem>
</List>
</Paper>
<Paper variant="outlined">
<List className={clsx(classes.list, 'w-50')}>
<ListItem className={classes.title}>
<Typography>{Tr(T.Ownership)}</Typography>
</ListItem>
<Divider />
<ListItem>
<Typography>{Tr(T.Owner)}</Typography>
<Typography>{UNAME}</Typography>
</ListItem>
<ListItem>
<Typography>{Tr(T.Group)}</Typography>
<Typography>{GNAME}</Typography>
</ListItem>
</List>
</Paper>
</Grid>
</Grid>
)
})
Info.propTypes = {
data: PropTypes.object.isRequired
}
Info.defaultProps = {
data: {}
}
Info.displayName = 'Info'
export default Info

View File

@ -0,0 +1,32 @@
import { makeStyles } from '@material-ui/core'
export default makeStyles(theme => ({
marginBottom: {
marginBottom: theme.spacing(2)
},
list: {
'& p': {
...theme.typography.body2,
overflow: 'hidden',
textOverflow: 'ellipsis'
},
'&.w-50 > *': {
'& > p, & > span': {
width: '50%'
}
},
'&.w-25 > *': {
'& > p, & > span': {
width: '25%'
}
}
},
title: {
'& p.bold': {
fontWeight: theme.typography.fontWeightBold
}
},
alignToRight: {
textAlign: 'right'
}
}))

View File

@ -0,0 +1,78 @@
import React, { useEffect } from 'react'
import { Container, Box } from '@material-ui/core'
import { Trash as DeleteIcon } from 'iconoir-react'
import { useAuth } from 'client/features/Auth'
import { useVm, useVmApi } from 'client/features/One'
import { useGeneralApi } from 'client/features/General'
import { useFetch, useSearch } from 'client/hooks'
import { ListHeader, ListCards } from 'client/components/List'
import { VirtualMachineCard } from 'client/components/Cards'
// import { DialogRequest } from 'client/components/Dialogs'
// import Information from 'client/containers/VirtualMachines/Sections/info'
import { T } from 'client/constants'
import { filterDoneVms } from 'client/models/VirtualMachine'
function VirtualMachines () {
// const [showDialog, setShowDialog] = useState(false)
const vms = useVm()
const { getVm, getVms, terminateVm } = useVmApi()
const { filterPool } = useAuth()
const { enqueueSuccess } = useGeneralApi()
const { fetchRequest, loading, reloading } = useFetch(getVms)
const { result, handleChange } = useSearch({
list: vms,
listOptions: { shouldSort: true, keys: ['ID', 'NAME'] }
})
useEffect(() => { fetchRequest() }, [filterPool])
// const handleCancel = () => setShowDialog(false)
return (
<Container disableGutters>
<ListHeader
title={T.VMs}
reloadButtonProps={{
onClick: () => fetchRequest(undefined, { reload: true }),
isSubmitting: Boolean(loading || reloading)
}}
searchProps={{ handleChange }}
/>
<Box p={3}>
<ListCards
list={result ?? filterDoneVms(vms)}
isLoading={vms.length === 0 && loading}
gridProps={{ 'data-cy': 'vms' }}
CardComponent={VirtualMachineCard}
cardsProps={({ value: { ID, NAME } }) => ({
actions: [
{
handleClick: () => terminateVm(ID)
.then(() => enqueueSuccess(`VM terminate - ID: ${ID}`))
.then(() => fetchRequest(undefined, { reload: true })),
icon: <DeleteIcon color='error' />,
cy: 'vm-delete'
}
]
})}
/>
</Box>
{/* {showDialog !== false && (
<DialogRequest
request={() => getVm(showDialog.id)}
dialogProps={{ handleCancel, ...showDialog }}
>
{({ data }) => <Information data={data} />}
</DialogRequest>
)} */}
</Container>
)
}
export default VirtualMachines

View File

@ -50,16 +50,12 @@ const Webconsole = () => {
const classes = useStyles()
const [listening, setListening] = useState(false)
const [response, setResponse] = useState([])
const { getHooks } = useSocket()
const { getHooksSocket } = useSocket()
const toggleListening = () => setListening(list => !list)
useEffect(() => {
listening
? getHooks.on(data => setResponse(prev => [...prev, data]))
: getHooks.off()
return getHooks.off
listening && getHooksSocket(data => setResponse(prev => [...prev, data]))
}, [listening])
return (

View File

@ -17,6 +17,7 @@ import * as React from 'react'
import { render } from 'react-dom'
import { createStore } from 'client/store'
import rootReducer from 'client/store/reducers'
import App from 'client/dev/_app'
const { store } = createStore({ initState: window.REDUX_DATA })
@ -29,7 +30,5 @@ if (process.env.NODE_ENV === 'development' && module.hot) {
render(<SyncApp store={store} />, document.getElementById('root'))
})
module.hot.accept('../reducers', () => {
store.replaceReducer(require('../reducers').default)
})
module.hot.accept('../store/reducers', () => store.replaceReducer(rootReducer))
}

View File

@ -5,6 +5,12 @@ export const changeZone = createAction('Change zone')
export const changeLoading = createAction('Change loading')
export const changeTitle = createAction('Change title')
export const enqueueSnackbar = createAction('Enqueue snackbar')
export const dismissSnackbar = createAction('Dismiss snackbar')
export const deleteSnackbar = createAction('Delete snackbar')
export const enqueueSnackbar = createAction(
'Enqueue snackbar',
(payload = {}) => {
if (payload?.message?.length > 0) return { payload }
}
)

View File

@ -1,8 +1,7 @@
import { useDispatch, useSelector } from 'react-redux'
import * as actions from 'client/features/General/actions'
const generateKey = () => new Date().getTime() + Math.random()
import { generateKey } from 'client/utils'
export const useGeneral = () => (
useSelector(state => state.general)
@ -17,15 +16,6 @@ export const useGeneralApi = () => {
changeTitle: title => dispatch(actions.changeTitle(title)),
changeZone: zone => dispatch(actions.changeZone(zone)),
enqueueSnackbar: notification => {
const key = notification.options && notification.options.key
return dispatch(actions.enqueueSnackbar({
key: key || generateKey(),
message: String(notification.message) || '',
options: notification.options || {}
}))
},
// dismiss all if no key has been defined
dismissSnackbar: key => dispatch(
actions.dismissSnackbar({ key, dismissAll: !key })
@ -34,6 +24,13 @@ export const useGeneralApi = () => {
actions.deleteSnackbar({ key })
),
enqueueSnackbar: ({ message, options = {} } = {}) => dispatch(
actions.enqueueSnackbar({
key: generateKey(),
message,
options
})
),
enqueueSuccess: message => dispatch(
actions.enqueueSnackbar({
key: generateKey(),
@ -45,14 +42,14 @@ export const useGeneralApi = () => {
actions.enqueueSnackbar({
key: generateKey(),
message,
options: { variant: 'success' }
options: { variant: 'error' }
})
),
enqueueInfo: message => dispatch(
actions.enqueueSnackbar({
key: generateKey(),
message,
options: { variant: 'success' }
options: { variant: 'info' }
})
)
}

View File

@ -1,6 +1,7 @@
import { createSlice } from '@reduxjs/toolkit'
import * as actions from 'client/features/General/actions'
import { generateKey } from 'client/utils'
const initial = {
zone: 0,
@ -84,12 +85,12 @@ const { reducer } = createSlice({
isLoading: false,
notifications: [
...state.notifications,
{
key: new Date().getTime() + Math.random(),
(payload?.length > 0 && {
key: generateKey(),
message: payload,
options: { variant: 'error' }
}
]
})
].filter(Boolean)
})
)
}

View File

@ -1,5 +1,7 @@
import { createSlice } from '@reduxjs/toolkit'
import { socketEventState } from 'client/features/One/socket/actions'
const initial = {
requests: {},
@ -35,6 +37,10 @@ const { actions, reducer } = createSlice({
extraReducers: builder => {
builder
.addCase('logout', () => initial)
.addCase(
socketEventState.fulfilled,
(state, { payload }) => ({ ...state, ...payload })
)
.addMatcher(
({ type }) => type.includes('/pool') && type.endsWith('/pending'),
(state, { meta, type }) => {

View File

@ -0,0 +1,138 @@
import { createAsyncThunk } from '@reduxjs/toolkit'
import * as actions from 'client/features/General/actions'
import { generateKey } from 'client/utils'
const MESSAGE_PROVISION_SUCCESS_CREATED = 'Provision successfully created'
const COMMANDS = {
create: 'create',
update: 'update',
delete: 'delete'
}
const RESOURCES = {
acl: 'acl',
app: 'apps',
cluster: 'clusters',
datastore: 'datastores',
file: 'files',
group: 'groups',
host: 'hosts',
image: 'images',
marketplace: 'marketplaces',
secgroups: 'securityGroups',
template: 'templates',
user: 'users',
vdc: 'vdc',
vm: 'vms',
vmgroup: 'vmGroups',
vn: 'vNetworks',
vntemplate: 'vNetworksTemplates',
zone: 'zones',
document: {
100: 'applications',
101: 'applicationsTemplates',
102: 'providers',
103: 'provisions'
}
}
const getResourceFromEventApi = (eventApi = {}) => {
const { CALL: command = '', CALL_INFO: info = {} } = eventApi?.HOOK_MESSAGE
const { EXTRA: extra, RESULT: result, PARAMETERS } = info
// command: 'one.resourceName.action'
const [, resourceName, action] = command.split('.')
// success: 1 || error: 0
const success = result === '1'
const value = extra?.[String(resourceName).toUpperCase()]
const resource = RESOURCES[resourceName]
const name = resource?.[value?.TYPE] ?? resource
const [, { VALUE: output }] = PARAMETERS?.PARAMETER
?.filter(({ TYPE }) => TYPE === 'OUT')
return {
action,
name,
value,
success,
output
}
}
export const socketEventApi = createAsyncThunk(
'socket/event-api',
({ data }) => {
const { action, name, value, success, output } = getResourceFromEventApi(data)
// console.log({ action, name, value, success, output })
return (success && value && action !== COMMANDS.delete) ? { [name]: value } : {}
},
{
condition: payload => payload?.data?.HOOK_MESSAGE?.HOOK_TYPE === 'API'
}
)
export const socketEventState = createAsyncThunk(
'socket/event-state',
({ data }, { getState }) => {
// possible hook objects: VM, IMAGE, HOST
const { RESOURCE_ID, HOOK_OBJECT: name, [name]: value } = data?.HOOK_MESSAGE
// update the list if event returns resource value
if (!value || value === '') return
const { NAME, STATE, LCM_STATE } = value
// this won't be a document resource never
const resource = RESOURCES[String(name).toLowerCase()]
const currentList = getState()?.one?.[resource] ?? []
const exists = currentList.some(({ ID }) => ID === RESOURCE_ID)
// update if exists in current list, if not add it
const updatedList = exists
? currentList?.map(item => ({
...item,
...(item?.ID === RESOURCE_ID && {
NAME,
STATE,
...(item?.LCM_STATE && { LCM_STATE })
})
}))
: [value, ...currentList]
return { [resource]: updatedList }
},
{
condition: payload => payload?.data?.HOOK_MESSAGE?.HOOK_TYPE === 'STATE'
}
)
export const socketCreateProvision = createAsyncThunk(
'socket/create-provision',
(_, { dispatch }) => {
dispatch(actions.enqueueSnackbar({
key: generateKey(),
message: MESSAGE_PROVISION_SUCCESS_CREATED,
options: { variant: 'success' }
}))
},
{
condition: (payload = {}) => {
const { command, data } = payload
return (
command === 'create' &&
data === MESSAGE_PROVISION_SUCCESS_CREATED
)
}
}
)

View File

@ -8,3 +8,14 @@ export const getVms = createAction(
vmService.getVms,
response => ({ vms: response })
)
export const terminateVm = createAction(
'provider/delete',
payload => vmService.actionVm({
...payload,
action: {
params: { hard: false },
perform: 'terminate'
}
})
)

View File

@ -18,6 +18,7 @@ export const useVmApi = () => {
return {
getVm: id => unwrapDispatch(actions.getVm({ id })),
getVms: () => unwrapDispatch(actions.getVms())
getVms: () => unwrapDispatch(actions.getVms()),
terminateVm: id => unwrapDispatch(actions.terminateVm({ id }))
}
}

View File

@ -4,22 +4,35 @@ import { requestParams, RestClient } from 'client/utils'
import { poolRequest } from 'client/features/One/utils'
export const vmService = ({
getVm: ({ filter, id }) => {
getVm: async ({ filter, id }) => {
const name = Actions.VM_INFO
const { url, options } = requestParams(
{ filter, id },
{ name, ...Commands[name] }
)
return RestClient.get(url, options).then(res => {
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
const res = await RestClient.get(url, options)
return res?.data?.VM ?? {}
})
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
return res?.data?.VM ?? {}
},
getVms: data => {
const name = Actions.VM_POOL_INFO
const command = { name, ...Commands[name] }
return poolRequest(data, command, 'VM')
},
actionVm: async ({ action, id }) => {
const name = Actions.VM_ACTION
const { url, options } = requestParams(
{ action, id },
{ name, ...Commands[name] }
)
const res = await RestClient.put(url, options)
if (!res?.id || res?.id !== httpCodes.ok.id) throw res
return res?.data?.VM ?? {}
}
})

View File

@ -1,6 +1,5 @@
import useFetch from 'client/hooks/useFetch'
import useFetchAll from 'client/hooks/useFetchAll'
import useGeneral from 'client/hooks/useGeneral'
import useList from 'client/hooks/useList'
import useListForm from 'client/hooks/useListForm'
import useNearScreen from 'client/hooks/useNearScreen'
@ -10,7 +9,6 @@ import useSocket from 'client/hooks/useSocket'
export {
useFetch,
useFetchAll,
useGeneral,
useList,
useListForm,
useNearScreen,

View File

@ -1,54 +0,0 @@
import { useCallback } from 'react'
import { useSelector, useDispatch, shallowEqual } from 'react-redux'
import * as actions from 'client/actions/general'
export default function useGeneral () {
const {
zone,
isLoading,
isOpenMenu,
isFixMenu
} = useSelector(state => state?.General, shallowEqual)
const dispatch = useDispatch()
const fixMenu = useCallback(isFixed => dispatch(actions.fixMenu(isFixed)), [
dispatch
])
const openMenu = useCallback(isOpen => dispatch(actions.openMenu(isOpen)), [
dispatch
])
const changeZone = useCallback(zone => dispatch(actions.changeZone(zone)), [
dispatch
])
const changeLoading = useCallback(
loading => dispatch(actions.changeLoading(loading)),
[dispatch]
)
const showSuccess = useCallback(
({ message }) => dispatch(actions.enqueueSuccess(message)),
[dispatch]
)
const showError = useCallback(
({ message }) => dispatch(actions.enqueueError(message)),
[dispatch]
)
return {
isFixMenu,
isLoading,
isOpenMenu,
zone,
changeZone,
openMenu,
fixMenu,
changeLoading,
showSuccess,
showError
}
}

View File

@ -1,24 +1,20 @@
import { useContext, useMemo } from 'react'
import { useContext, useCallback } from 'react'
import { SOCKETS } from 'client/constants'
import { SocketContext } from 'client/providers/socketProvider'
const SOCKETS = {
hooks: 'hooks',
provision: 'provision'
}
export default function useSocket () {
const { socket, isConnected } = useContext(SocketContext)
const getHooks = useMemo(() => ({
on: (func) => isConnected && socket.on(SOCKETS.hooks, func),
off: () => isConnected && socket.off()
const getHooksSocket = useCallback(func => ({
on: () => isConnected && socket.on(SOCKETS.hooks, func),
off: () => isConnected && socket.off(SOCKETS.hooks, func)
}), [socket, isConnected])
const getProvision = useMemo(() => ({
on: (func) => isConnected && socket.on(SOCKETS.provision, func),
off: () => isConnected && socket.off()
const getProvisionSocket = useCallback(func => ({
on: () => isConnected && socket.on(SOCKETS.provision, func),
off: () => isConnected && socket.off(SOCKETS.provision, func)
}), [socket, isConnected])
return { isConnected, getHooks, getProvision }
return { isConnected, getHooksSocket, getProvisionSocket }
}

View File

@ -0,0 +1,10 @@
import { STATES, VM_STATES, VM_LCM_STATES } from 'client/constants'
export const filterDoneVms = (vms = []) =>
vms.filter(({ STATE }) => VM_STATES[STATE]?.name !== STATES.DONE)
export const getState = ({ STATE, LCM_STATE } = {}) => {
const state = VM_STATES[+STATE]
return state?.name === STATES.ACTIVE ? VM_LCM_STATES[+LCM_STATE] : state
}

View File

@ -10,19 +10,19 @@ const useStyles = makeStyles(({ palette }) => ({
wordBreak: 'break-all'
},
variantSuccess: {
backgroundColor: `${palette.success.main} !important`,
backgroundColor: palette.success.main,
color: palette.success.contrastText
},
variantError: {
backgroundColor: `${palette.error.main} !important`,
backgroundColor: palette.error.main,
color: palette.error.contrastText
},
variantInfo: {
backgroundColor: `${palette.debug.main} !important`,
backgroundColor: palette.debug.main,
color: palette.debug.contrastText
},
variantWarning: {
backgroundColor: `${palette.warning.main} !important`,
backgroundColor: palette.warning.main,
color: palette.warning.contrastText
}
}))

View File

@ -1,11 +1,13 @@
import React, { createContext, useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
import io from 'socket.io-client'
import { WEBSOCKET_URL } from 'client/constants'
import socketIO from 'socket.io-client'
import { useSelector, useDispatch } from 'react-redux'
const websocket = query => io({ path: WEBSOCKET_URL, query })
import { WEBSOCKET_URL, SOCKETS } from 'client/constants'
import * as sockets from 'client/features/One/socket/actions'
const createWebsocket = query => socketIO({ path: WEBSOCKET_URL, query })
const CONNECT = 'connect'
const DISCONNECT = 'disconnect'
@ -15,6 +17,8 @@ export const SocketContext = createContext(null)
const SocketProvider = ({ children }) => {
const [socket, setSocket] = useState({})
const [isConnected, setConnected] = useState(false)
const dispatch = useDispatch()
const { jwt, zone } = useSelector(state => ({
zone: state?.general?.zone,
jwt: state?.auth?.jwt
@ -23,14 +27,23 @@ const SocketProvider = ({ children }) => {
useEffect(() => {
if (!jwt) return
const client = websocket({ token: jwt, zone })
const client = createWebsocket({ token: jwt, zone })
setSocket(client)
client.on(CONNECT, () => setConnected(true))
client.on(DISCONNECT, () => setConnected(false))
setSocket(client)
client.on(SOCKETS.hooks, data => {
dispatch(sockets.socketEventState(data))
})
client.on(SOCKETS.provision, data => {
dispatch(sockets.socketCreateProvision(data))
})
return () => {
setSocket(null)
return client.disconnect()
client?.disconnect()
}
}, [jwt, zone])

View File

@ -1,99 +0,0 @@
/* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const { Actions: UserActions } = require('../actions/user')
const {
JWT_NAME,
FILTER_POOL,
DEFAULT_LANGUAGE,
DEFAULT_SCHEME
} = require('client/constants')
const jwt =
typeof window !== 'undefined'
? window.localStorage.getItem(JWT_NAME) ??
window.sessionStorage.getItem(JWT_NAME) ??
null
: null
const initial = {
jwt,
user: null,
group: null,
error: null,
filterPool: FILTER_POOL.ALL_RESOURCES,
settings: {
scheme: DEFAULT_SCHEME,
lang: DEFAULT_LANGUAGE,
disableanimations: 'YES'
},
isLoginInProcess: false,
isLoading: false,
firstRender: true
}
const authentication = (state = initial, action) => {
switch (action.type) {
case UserActions.START_AUTH:
return {
...state,
error: null,
firstRender: false,
isLoading: true
}
case UserActions.SUCCESS_AUTH:
return {
...state,
error: null,
firstRender: false,
isLoading: false,
...action.payload
}
case UserActions.SELECT_FILTER_GROUP:
return {
...state,
isLoading: false,
isLoginInProcess: false,
...action.payload
}
case UserActions.CHANGE_SETTINGS:
return {
...state,
settings: {
...initial.settings,
...action.payload
}
}
case UserActions.FAILURE_AUTH:
return {
...state,
jwt: null,
firstRender: false,
isLoading: false,
isLoginInProcess: false,
...action.payload
}
case UserActions.LOGOUT:
return {
...initial,
jwt: null,
firstRender: false
}
default:
return state
}
}
module.exports = authentication

View File

@ -1,75 +0,0 @@
/* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const { Actions: PoolActions } = require('../actions/pool')
const { Actions: UserActions } = require('../actions/user')
const { Actions: GeneralActions } = require('../actions/general')
const initial = {
zone: 0,
notifications: [],
isLoading: false,
isOpenMenu: false,
isFixMenu: false
}
const General = (state = initial, action) => {
switch (action.type) {
case PoolActions.START_ONE_REQUEST:
return { ...state, isLoading: true }
case PoolActions.SUCCESS_ONE_REQUEST:
return { ...state, isLoading: false }
case PoolActions.FAILURE_ONE_REQUEST:
return { ...state, isLoading: false }
case GeneralActions.ENQUEUE_SNACKBAR:
return {
...state,
notifications: [
...state.notifications,
{ key: action.key, ...action.notification }
]
}
case GeneralActions.CLOSE_SNACKBAR:
return {
...state,
notifications: state.notifications.map(notification =>
action.dismissAll || notification.key === action.key
? { ...notification, dismissed: true }
: { ...notification }
)
}
case GeneralActions.REMOVE_SNACKBAR:
return {
...state,
notifications: state.notifications.filter(
notification => notification.key !== action.key
)
}
case GeneralActions.CHANGE_LOADING:
return { ...state, ...action.payload }
case GeneralActions.CHANGE_ZONE:
return { ...state, ...action.payload }
case GeneralActions.TOGGLE_MENU:
return { ...state, isOpenMenu: action.isOpen }
case GeneralActions.FIX_MENU:
return { ...state, isFixMenu: action.isFixed }
case UserActions.LOGOUT:
return { ...initial }
default:
return state
}
}
module.exports = General

View File

@ -1,30 +0,0 @@
/* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const { combineReducers } = require('redux')
const Opennebula = require('./opennebula')
const Zendesk = require('./zendesk')
const General = require('./general')
const Authenticated = require('./auth')
const rootReducers = () =>
combineReducers({
Authenticated,
Opennebula,
Zendesk,
General
})
module.exports = rootReducers

View File

@ -1,57 +0,0 @@
/* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const { Actions: PoolActions } = require('../actions/pool')
const { Actions: UserActions } = require('../actions/user')
const initial = {
vm: [],
templates: [],
applications: [],
applicationsTemplates: [],
datastores: [],
virtualRouters: [],
vmGroups: [],
images: [],
files: [],
marketplaces: [],
apps: [],
vNetworks: [],
vNetworksTemplates: [],
securityGroups: [],
clusters: [],
hosts: [],
zones: [],
users: [],
groups: [],
vdc: [],
acl: [],
provisionsTemplates: [],
providers: [],
provisions: []
}
const Opennebula = (state = initial, action) => {
switch (action.type) {
case PoolActions.SUCCESS_ONE_REQUEST:
return { ...state, ...action.payload }
case UserActions.LOGOUT:
return { ...initial }
default:
return state
}
}
module.exports = Opennebula

View File

@ -1,37 +0,0 @@
/* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const initial = {
user: {
name: ''
},
tickets: []
}
const Zendesk = (state = initial, action) => {
switch (action.type) {
case 'SETTICKET': {
const { tickets } = state
return {
...state,
tickets
}
}
default:
return state
}
}
module.exports = Zendesk

View File

@ -1,6 +1,10 @@
import loadable from '@loadable/component'
import { Code as DevIcon } from 'iconoir-react'
import {
Code as DevIcon,
ViewGrid as VmIcon
} from 'iconoir-react'
const VirtualMachines = loadable(() => import('client/containers/VirtualMachines'), { ssr: false })
const TestApi = loadable(() => import('client/containers/TestApi'), { ssr: false })
const WebConsole = loadable(() => import('client/containers/WebConsole'), { ssr: false })
@ -11,6 +15,14 @@ export const PATH = {
}
export const ENDPOINTS = [
{
label: 'VMs',
path: PATH.VIRTUAL_MACHINES,
devMode: true,
sidebar: true,
icon: VmIcon,
Component: VirtualMachines
},
{
label: 'Test API',
path: PATH.TEST_API,

View File

@ -2,10 +2,7 @@ import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'
import thunkMiddleware from 'redux-thunk'
import * as General from 'client/features/General'
import * as Auth from 'client/features/Auth'
import * as One from 'client/features/One'
import rootReducer from 'client/store/reducers'
import { isDevelopment } from 'client/utils'
export const createStore = ({ initState = {}, services }) => {
@ -18,11 +15,7 @@ export const createStore = ({ initState = {}, services }) => {
middleware.push(thunkMiddleware.withExtraArgument({ services }))
const store = configureStore({
reducer: {
general: General.reducer,
auth: Auth.reducer,
one: One.reducer
},
reducer: rootReducer,
devTools: isDevelopment(),
middleware,
preloadedState: initState

View File

@ -0,0 +1,12 @@
const { combineReducers } = require('redux')
const General = require('client/features/General')
const Auth = require('client/features/Auth')
const One = require('client/features/One')
const rootReducer = combineReducers({
general: General.reducer,
auth: Auth.reducer,
one: One.reducer
})
module.exports = rootReducer

View File

@ -1,166 +0,0 @@
import PropTypes from 'prop-types'
import { PROVIDERS_TYPES, PROVISIONS_TYPES } from 'client/constants'
const providerTypes = Object.values(PROVIDERS_TYPES).map(({ id }) => id)
const provisionTypes = Object.values(PROVISIONS_TYPES).map(({ id }) => id)
export const UserInput = PropTypes.shape({
name: PropTypes.string.isRequired,
description: PropTypes.string,
type: PropTypes.oneOf([
'text',
'text64',
'password',
'number',
'number-float',
'range',
'range-float',
'boolean',
'list',
'array',
'list-multiple'
]).isRequired,
options: PropTypes.arrayOf(
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
),
min_value: PropTypes.number,
max_value: PropTypes.number,
default: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
])
})
export const ProviderType = PropTypes.oneOf(providerTypes)
export const ProvisionType = PropTypes.oneOf(provisionTypes)
export const ProvisionHost = PropTypes.shape({
im_mad: PropTypes.string.isRequired,
vm_mad: PropTypes.string.isRequired,
provision: PropTypes.shape({
count: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
hostname: PropTypes.string
})
})
export const ProviderPlainInfo = PropTypes.shape({
image: PropTypes.string,
location_key: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string)
]),
provision_type: ProvisionType.isRequired
})
export const ProviderTemplate = PropTypes.shape({
name: PropTypes.string.isRequired,
description: PropTypes.string,
provider: ProviderType.isRequired,
plain: ProviderPlainInfo.isRequired,
connection: PropTypes.objectOf(PropTypes.string),
inputs: PropTypes.arrayOf(UserInput)
})
export const ProvisionTemplate = PropTypes.shape({
name: PropTypes.string.isRequired,
description: PropTypes.string,
provider: ProviderType.isRequired,
provision_type: ProvisionType.isRequired,
defaults: PropTypes.shape({
provision: PropTypes.shape({
provider_name: PropTypes.string
})
}).isRequired,
hosts: PropTypes.arrayOf(ProvisionHost),
inputs: PropTypes.arrayOf(UserInput)
})
export const Provider = PropTypes.shape({
ID: PropTypes.string.isRequired,
UID: PropTypes.string.isRequired,
GID: PropTypes.string.isRequired,
UNAME: PropTypes.string.isRequired,
GNAME: PropTypes.string.isRequired,
NAME: PropTypes.string.isRequired,
TYPE: PropTypes.string.isRequired,
PERMISSIONS: PropTypes.shape({
OWNER_U: PropTypes.oneOf(['0', '1']).isRequired,
OWNER_M: PropTypes.oneOf(['0', '1']).isRequired,
OWNER_A: PropTypes.oneOf(['0', '1']).isRequired,
GROUP_U: PropTypes.oneOf(['0', '1']).isRequired,
GROUP_M: PropTypes.oneOf(['0', '1']).isRequired,
GROUP_A: PropTypes.oneOf(['0', '1']).isRequired,
OTHER_U: PropTypes.oneOf(['0', '1']).isRequired,
OTHER_M: PropTypes.oneOf(['0', '1']).isRequired,
OTHER_A: PropTypes.oneOf(['0', '1']).isRequired
}).isRequired,
TEMPLATE: PropTypes.shape({
PLAIN: ProviderPlainInfo,
PROVISION_BODY: PropTypes.oneOfType([
// encrypted
PropTypes.string,
PropTypes.shape({
provider: ProviderType,
connection: PropTypes.objectOf(PropTypes.string),
registration_time: PropTypes.number,
description: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
inputs: PropTypes.arrayOf(UserInput)
}).isRequired
])
})
})
const ProvisionInfrastructure = PropTypes.shape({
id: PropTypes.number.isRequired,
name: PropTypes.string.isRequired
})
export const Provision = PropTypes.shape({
ID: PropTypes.string.isRequired,
UID: PropTypes.string.isRequired,
GID: PropTypes.string.isRequired,
UNAME: PropTypes.string.isRequired,
GNAME: PropTypes.string.isRequired,
NAME: PropTypes.string.isRequired,
TYPE: PropTypes.string.isRequired,
PERMISSIONS: PropTypes.shape({
OWNER_U: PropTypes.oneOf(['0', '1']).isRequired,
OWNER_M: PropTypes.oneOf(['0', '1']).isRequired,
OWNER_A: PropTypes.oneOf(['0', '1']).isRequired,
GROUP_U: PropTypes.oneOf(['0', '1']).isRequired,
GROUP_M: PropTypes.oneOf(['0', '1']).isRequired,
GROUP_A: PropTypes.oneOf(['0', '1']).isRequired,
OTHER_U: PropTypes.oneOf(['0', '1']).isRequired,
OTHER_M: PropTypes.oneOf(['0', '1']).isRequired,
OTHER_A: PropTypes.oneOf(['0', '1']).isRequired
}).isRequired,
TEMPLATE: PropTypes.shape({
BODY: PropTypes.shape({
name: PropTypes.string,
description: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number
]),
start_time: PropTypes.number,
state: PropTypes.number,
provider: PropTypes.string,
provision: PropTypes.shape({
infrastructure: PropTypes.shape({
clusters: PropTypes.arrayOf(ProvisionInfrastructure),
datastores: PropTypes.arrayOf(ProvisionInfrastructure),
networks: PropTypes.arrayOf(ProvisionInfrastructure)
}),
resource: PropTypes.object
}),
image: PropTypes.string,
provision_type: ProvisionType
}).isRequired
})
})

View File

@ -4,6 +4,8 @@ export const fakeDelay = ms => new Promise(resolve => setTimeout(resolve, ms))
export const isExternalURL = url => RegExp(/^(http|https):/g).test(url)
export const generateKey = () => new Date().getTime() + Math.random()
export function sanitize (strings, ...values) {
const dirty = strings.reduce((prev, next, i) =>
`${prev}${next}${values[i] || ''}`, '')

View File

@ -8,7 +8,7 @@ const { createStore, compose, applyMiddleware } = require('redux')
const thunk = require('redux-thunk').default
const { ServerStyleSheets } = require('@material-ui/core/styles')
const { ChunkExtractor } = require('@loadable/server')
const rootReducer = require('client/reducers')
const rootReducer = require('client/store/reducers')
const { getConfig } = require('server/utils/yml')
const {
availableLanguages, defaultWebpackMode, defaultApps, defaultFileStats
@ -59,7 +59,7 @@ router.get('*', (req, res) => {
const extractor = new ChunkExtractor({ statsFile })
// SSR redux store
store = createStore(rootReducer(), composeEnhancer(applyMiddleware(thunk)))
store = createStore(rootReducer, composeEnhancer(applyMiddleware(thunk)))
storeRender = `<script id="preloadState">window.__PRELOADED_STATE__ = ${
JSON.stringify(store.getState()).replace(/</g, '\\u003c')
}</script>`

View File

@ -41,7 +41,6 @@ const websockets = (appServer = {}) => {
}
}
).listen(appServer)
defaultFilesWebsockets.forEach(file => {
try {
// eslint-disable-next-line global-require
@ -51,7 +50,7 @@ const websockets = (appServer = {}) => {
fileInfo.main(io)
}
} catch (error) {
if (error instanceof Error && error.code === 'MODULE_NOT_FOUND') {
if (error instanceof Error) {
const config = defaultConfigErrorMessage
config.type = error.message
messageTerminal(config)