diff --git a/virtweb_backend/src/actors/libvirt_actor.rs b/virtweb_backend/src/actors/libvirt_actor.rs index ae29d50..5cf00ec 100644 --- a/virtweb_backend/src/actors/libvirt_actor.rs +++ b/virtweb_backend/src/actors/libvirt_actor.rs @@ -49,7 +49,7 @@ pub struct HypervisorNodeInfo { pub number_of_numa_cell: u32, pub number_of_cpu_socket_per_node: u32, pub number_of_core_per_sockets: u32, - pub number_of_threads_per_sockets: u32, + pub number_of_threads_per_core: u32, } impl Handler for LibVirtActor { @@ -72,7 +72,7 @@ impl Handler for LibVirtActor { number_of_numa_cell: node.nodes, number_of_cpu_socket_per_node: node.sockets, number_of_core_per_sockets: node.cores, - number_of_threads_per_sockets: node.threads, + number_of_threads_per_core: node.threads, }, }) } diff --git a/virtweb_frontend/package-lock.json b/virtweb_frontend/package-lock.json index cc2386b..8fd68f9 100644 --- a/virtweb_frontend/package-lock.json +++ b/virtweb_frontend/package-lock.json @@ -15,15 +15,18 @@ "@mdi/react": "^1.6.1", "@mui/icons-material": "^5.14.7", "@mui/material": "^5.14.7", + "@mui/x-charts": "^6.0.0-alpha.9", "@mui/x-data-grid": "^6.12.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/humanize-duration": "^3.27.1", "@types/jest": "^27.5.2", "@types/node": "^16.18.48", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "filesize": "^10.0.12", + "humanize-duration": "^3.29.0", "mui-file-input": "^3.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -3590,6 +3593,38 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/@mui/x-charts": { + "version": "6.0.0-alpha.9", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-6.0.0-alpha.9.tgz", + "integrity": "sha512-2DVTbyxsm3g0D6kztQP9W4W9OOGeIQ/g6Ip6gjHj2wOOqkDB36bZxwVG/HlJuaVFBL001vI2VkYJYy+helw9gA==", + "dependencies": { + "@babel/runtime": "^7.22.11", + "clsx": "^2.0.0", + "d3-color": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.4.1", + "@mui/system": "^5.4.1", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, "node_modules/@mui/x-data-grid": { "version": "6.12.1", "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.12.1.tgz", @@ -4524,6 +4559,11 @@ "@types/node": "*" } }, + "node_modules/@types/humanize-duration": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.27.1.tgz", + "integrity": "sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -6934,6 +6974,100 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -9448,6 +9582,11 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-duration": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.29.0.tgz", + "integrity": "sha512-G5wZGwYTLaQAmYqhfK91aw3xt6wNbJW1RnWDh4qP1PvF4T/jnkjx2RVhG5kzB2PGsYGTn+oSDBQp+dMdILLxcg==" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -9592,6 +9731,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -20455,6 +20602,19 @@ } } }, + "@mui/x-charts": { + "version": "6.0.0-alpha.9", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-6.0.0-alpha.9.tgz", + "integrity": "sha512-2DVTbyxsm3g0D6kztQP9W4W9OOGeIQ/g6Ip6gjHj2wOOqkDB36bZxwVG/HlJuaVFBL001vI2VkYJYy+helw9gA==", + "requires": { + "@babel/runtime": "^7.22.11", + "clsx": "^2.0.0", + "d3-color": "^3.1.0", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "prop-types": "^15.8.1" + } + }, "@mui/x-data-grid": { "version": "6.12.1", "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.12.1.tgz", @@ -21114,6 +21274,11 @@ "@types/node": "*" } }, + "@types/humanize-duration": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.27.1.tgz", + "integrity": "sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==" + }, "@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -22899,6 +23064,73 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==" + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "requires": { + "d3-path": "^3.1.0" + } + }, + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "requires": { + "d3-time": "1 - 3" + } + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -24747,6 +24979,11 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" }, + "humanize-duration": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.29.0.tgz", + "integrity": "sha512-G5wZGwYTLaQAmYqhfK91aw3xt6wNbJW1RnWDh4qP1PvF4T/jnkjx2RVhG5kzB2PGsYGTn+oSDBQp+dMdILLxcg==" + }, "iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -24848,6 +25085,11 @@ "side-channel": "^1.0.4" } }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, "ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", diff --git a/virtweb_frontend/package.json b/virtweb_frontend/package.json index 80235fb..ddc23dc 100644 --- a/virtweb_frontend/package.json +++ b/virtweb_frontend/package.json @@ -10,15 +10,18 @@ "@mdi/react": "^1.6.1", "@mui/icons-material": "^5.14.7", "@mui/material": "^5.14.7", + "@mui/x-charts": "^6.0.0-alpha.9", "@mui/x-data-grid": "^6.12.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/humanize-duration": "^3.27.1", "@types/jest": "^27.5.2", "@types/node": "^16.18.48", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "filesize": "^10.0.12", + "humanize-duration": "^3.29.0", "mui-file-input": "^3.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/virtweb_frontend/src/api/ServerApi.ts b/virtweb_frontend/src/api/ServerApi.ts index 08757a8..84b8328 100644 --- a/virtweb_frontend/src/api/ServerApi.ts +++ b/virtweb_frontend/src/api/ServerApi.ts @@ -30,7 +30,7 @@ interface HypervisorInfo { number_of_numa_cell: number; number_of_cpu_socket_per_node: number; number_of_core_per_sockets: number; - number_of_threads_per_sockets: number; + number_of_threads_per_core: number; }; } diff --git a/virtweb_frontend/src/routes/SysInfoRoute.tsx b/virtweb_frontend/src/routes/SysInfoRoute.tsx index 142774c..6a45308 100644 --- a/virtweb_frontend/src/routes/SysInfoRoute.tsx +++ b/virtweb_frontend/src/routes/SysInfoRoute.tsx @@ -1,6 +1,21 @@ +import { mdiInformation, mdiMemory, mdiPackageVariantClosed } from "@mdi/js"; +import Icon from "@mdi/react"; +import { + Box, + Grid, + Table, + TableBody, + TableCell, + TableRow, + Typography, +} from "@mui/material"; +import { PieChart } from "@mui/x-charts"; import React from "react"; import { ServerApi, ServerSystemInfo } from "../api/ServerApi"; import { AsyncWidget } from "../widgets/AsyncWidget"; +import { VirtWebPaper } from "../widgets/VirtWebPaper"; +import { VirtWebRouteContainer } from "../widgets/VirtWebRouteContainer"; +import humanizeDuration from "humanize-duration"; export function SysInfoRoute(): React.ReactElement { const [info, setInfo] = React.useState(); @@ -22,5 +37,210 @@ export function SysInfoRoute(): React.ReactElement { export function SysInfoRouteInner(p: { info: ServerSystemInfo; }): React.ReactElement { - return <>todo; + const sumDiskUsage = p.info.system.disks.reduce( + (prev, disk) => { + return { + used: prev.used + disk.total_space - disk.available_space, + free: prev.free + disk.available_space, + }; + }, + { used: 0, free: 0 } + ); + + return ( + + + {/* Memory */} + + + Memory + + + + + {/* Disk usage */} + + + Disk usage + + + + + {/* CPU usage */} + + + CPU usage + + + + + + } + entries={[ + { + label: "Load", + value: `${p.info.system.load_average.one} ${p.info.system.load_average.five} ${p.info.system.load_average.fifteen}`, + }, + { + label: "Uptime", + value: humanizeDuration(p.info.system.uptime * 1000), + }, + { + label: "Bootime", + value: new Date(p.info.system.boot_time * 1000).toString(), + }, + { + label: "Hypvervisor type", + value: p.info.hypervisor.type, + }, + ]} + /> + + } + entries={[ + { label: "Brand", value: p.info.system.global_cpu_info.brand }, + { + label: "Vendor ID", + value: p.info.system.global_cpu_info.vendor_id, + }, + { + label: "CPU usage", + value: p.info.system.global_cpu_info.cpu_usage, + }, + { + label: "Name", + value: p.info.system.global_cpu_info.name, + }, + { + label: "CPU model", + value: p.info.hypervisor.node.cpu_model, + }, + { + label: "CPU frequency (MHz)", + value: p.info.hypervisor.node.cpu_frequency_mhz, + }, + { + label: "Number of socket", + value: p.info.hypervisor.node.number_of_cpu_socket_per_node, + }, + { + label: "Number of cores per socket", + value: p.info.hypervisor.node.number_of_core_per_sockets, + }, + { + label: "Number of threads per core", + value: p.info.hypervisor.node.number_of_threads_per_core, + }, + ]} + /> + + } + entries={[ + { label: "Name", value: p.info.system.name }, + { label: "Host name", value: p.info.system.host_name }, + { label: "Long OS version", value: p.info.system.long_os_version }, + { label: "Kernel version", value: p.info.system.kernel_version }, + ]} + /> + + ); +} + +function SysInfoDetailsTable(p: { + label: string; + icon: React.ReactElement; + entries: Array<{ label: string; value: string | number }>; +}): React.ReactElement { + return ( + + {p.icon} {p.label} + + } + > + + + {p.entries.map((e, c) => ( + + + {e.label} + + {e.value} + + ))} + +
+
+ ); } diff --git a/virtweb_frontend/src/widgets/VirtWebPaper.tsx b/virtweb_frontend/src/widgets/VirtWebPaper.tsx index 88fd0bb..79dcbbc 100644 --- a/virtweb_frontend/src/widgets/VirtWebPaper.tsx +++ b/virtweb_frontend/src/widgets/VirtWebPaper.tsx @@ -1,8 +1,8 @@ import { Paper, Typography } from "@mui/material"; -import { PropsWithChildren } from "react"; +import React, { PropsWithChildren } from "react"; export function VirtWebPaper( - p: { label: string } & PropsWithChildren + p: { label: string | React.ReactElement } & PropsWithChildren ): React.ReactElement { return (