Display live and cached consumption on dashboard
This commit is contained in:
parent
539703b904
commit
1784a0a1f8
350
central_frontend/package-lock.json
generated
350
central_frontend/package-lock.json
generated
@ -15,6 +15,7 @@
|
|||||||
"@mdi/react": "^1.6.1",
|
"@mdi/react": "^1.6.1",
|
||||||
"@mui/icons-material": "^6.0.1",
|
"@mui/icons-material": "^6.0.1",
|
||||||
"@mui/material": "^6.0.1",
|
"@mui/material": "^6.0.1",
|
||||||
|
"@mui/x-charts": "^7.15.0",
|
||||||
"@mui/x-date-pickers": "^7.15.0",
|
"@mui/x-date-pickers": "^7.15.0",
|
||||||
"date-and-time": "^3.5.0",
|
"date-and-time": "^3.5.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
@ -1377,6 +1378,93 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mui/x-charts": {
|
||||||
|
"version": "7.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.15.0.tgz",
|
||||||
|
"integrity": "sha512-eAyrLWMrFt6NKKca1vCWvVoThapGSdTzvDSY76CiA5Q1eOzZIhIriafh26QFqQLSuLYnCwHdX+gBVmCoZorcWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.4",
|
||||||
|
"@mui/utils": "^5.16.6",
|
||||||
|
"@mui/x-charts-vendor": "7.15.0",
|
||||||
|
"@react-spring/rafz": "^9.7.4",
|
||||||
|
"@react-spring/web": "^9.7.4",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"prop-types": "^15.8.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.9.0",
|
||||||
|
"@emotion/styled": "^11.8.1",
|
||||||
|
"@mui/material": "^5.15.14 || ^6.0.0",
|
||||||
|
"@mui/system": "^5.15.14 || ^6.0.0",
|
||||||
|
"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-charts-vendor": {
|
||||||
|
"version": "7.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.15.0.tgz",
|
||||||
|
"integrity": "sha512-5PNzV3//gdS3jlsbvAc/kj6k7KTikjNhprXVaTIrqj9/Jm2MU0cNtmwDwDVkekXLpjeXGGT6nrIehb129GIinw==",
|
||||||
|
"license": "MIT AND ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.25.4",
|
||||||
|
"@types/d3-color": "^3.1.3",
|
||||||
|
"@types/d3-delaunay": "^6.0.4",
|
||||||
|
"@types/d3-interpolate": "^3.0.4",
|
||||||
|
"@types/d3-scale": "^4.0.8",
|
||||||
|
"@types/d3-shape": "^3.1.6",
|
||||||
|
"@types/d3-time": "^3.0.3",
|
||||||
|
"d3-color": "^3.1.0",
|
||||||
|
"d3-delaunay": "^6.0.4",
|
||||||
|
"d3-interpolate": "^3.0.1",
|
||||||
|
"d3-scale": "^4.0.2",
|
||||||
|
"d3-shape": "^3.2.0",
|
||||||
|
"d3-time": "^3.1.0",
|
||||||
|
"delaunator": "^5.0.1",
|
||||||
|
"robust-predicates": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mui/x-charts/node_modules/@mui/utils": {
|
||||||
|
"version": "5.16.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz",
|
||||||
|
"integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.23.9",
|
||||||
|
"@mui/types": "^7.2.15",
|
||||||
|
"@types/prop-types": "^15.7.12",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"prop-types": "^15.8.1",
|
||||||
|
"react-is": "^18.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mui-org"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^17.0.0 || ^18.0.0",
|
||||||
|
"react": "^17.0.0 || ^18.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mui/x-date-pickers": {
|
"node_modules/@mui/x-date-pickers": {
|
||||||
"version": "7.15.0",
|
"version": "7.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.15.0.tgz",
|
||||||
@ -1516,6 +1604,78 @@
|
|||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-spring/animated": {
|
||||||
|
"version": "9.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz",
|
||||||
|
"integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-spring/shared": "~9.7.4",
|
||||||
|
"@react-spring/types": "~9.7.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-spring/core": {
|
||||||
|
"version": "9.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz",
|
||||||
|
"integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-spring/animated": "~9.7.4",
|
||||||
|
"@react-spring/shared": "~9.7.4",
|
||||||
|
"@react-spring/types": "~9.7.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/react-spring/donate"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-spring/rafz": {
|
||||||
|
"version": "9.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.4.tgz",
|
||||||
|
"integrity": "sha512-mqDI6rW0Ca8IdryOMiXRhMtVGiEGLIO89vIOyFQXRIwwIMX30HLya24g9z4olDvFyeDW3+kibiKwtZnA4xhldA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@react-spring/shared": {
|
||||||
|
"version": "9.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz",
|
||||||
|
"integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-spring/rafz": "~9.7.4",
|
||||||
|
"@react-spring/types": "~9.7.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-spring/types": {
|
||||||
|
"version": "9.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.4.tgz",
|
||||||
|
"integrity": "sha512-iQVztO09ZVfsletMiY+DpT/JRiBntdsdJ4uqk3UJFhrhS8mIC9ZOZbmfGSRs/kdbNPQkVyzucceDicQ/3Mlj9g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@react-spring/web": {
|
||||||
|
"version": "9.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.4.tgz",
|
||||||
|
"integrity": "sha512-UMvCZp7I5HCVIleSa4BwbNxynqvj+mJjG2m20VO2yPoi2pnCYANy58flvz9v/YcXTAvsmL655FV3pm5fbr6akA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-spring/animated": "~9.7.4",
|
||||||
|
"@react-spring/core": "~9.7.4",
|
||||||
|
"@react-spring/shared": "~9.7.4",
|
||||||
|
"@react-spring/types": "~9.7.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@remix-run/router": {
|
"node_modules/@remix-run/router": {
|
||||||
"version": "1.19.1",
|
"version": "1.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz",
|
||||||
@ -1790,6 +1950,57 @@
|
|||||||
"@babel/types": "^7.20.7"
|
"@babel/types": "^7.20.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/d3-color": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-delaunay": {
|
||||||
|
"version": "6.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
|
||||||
|
"integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-interpolate": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-color": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-path": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-scale": {
|
||||||
|
"version": "4.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz",
|
||||||
|
"integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-time": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-shape": {
|
||||||
|
"version": "3.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz",
|
||||||
|
"integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/d3-path": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/d3-time": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||||
@ -2304,6 +2515,121 @@
|
|||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||||
},
|
},
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/d3-delaunay": {
|
||||||
|
"version": "6.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
|
||||||
|
"integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"delaunator": "5"
|
||||||
|
},
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-time": "1 - 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/date-and-time": {
|
"node_modules/date-and-time": {
|
||||||
"version": "3.5.0",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-3.5.0.tgz",
|
||||||
@ -2338,6 +2664,15 @@
|
|||||||
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/delaunator": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"robust-predicates": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/doctrine": {
|
"node_modules/doctrine": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||||
@ -3045,6 +3380,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"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==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||||
@ -3703,6 +4047,12 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/robust-predicates": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
|
||||||
|
"license": "Unlicense"
|
||||||
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.21.2",
|
"version": "4.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@mdi/react": "^1.6.1",
|
"@mdi/react": "^1.6.1",
|
||||||
"@mui/icons-material": "^6.0.1",
|
"@mui/icons-material": "^6.0.1",
|
||||||
"@mui/material": "^6.0.1",
|
"@mui/material": "^6.0.1",
|
||||||
|
"@mui/x-charts": "^7.15.0",
|
||||||
"@mui/x-date-pickers": "^7.15.0",
|
"@mui/x-date-pickers": "^7.15.0",
|
||||||
"date-and-time": "^3.5.0",
|
"date-and-time": "^3.5.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
26
central_frontend/src/api/EnergyApi.ts
Normal file
26
central_frontend/src/api/EnergyApi.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Api } from "@mui/icons-material";
|
||||||
|
import { APIClient } from "./ApiClient";
|
||||||
|
|
||||||
|
export class EnergyApi {
|
||||||
|
/**
|
||||||
|
* Get current house consumption
|
||||||
|
*/
|
||||||
|
static async CurrConsumption(): Promise<number> {
|
||||||
|
const data = await APIClient.exec({
|
||||||
|
method: "GET",
|
||||||
|
uri: "/energy/curr_consumption",
|
||||||
|
});
|
||||||
|
return data.data.consumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current cached consumption
|
||||||
|
*/
|
||||||
|
static async CachedConsumption(): Promise<number> {
|
||||||
|
const data = await APIClient.exec({
|
||||||
|
method: "GET",
|
||||||
|
uri: "/energy/cached_consumption",
|
||||||
|
});
|
||||||
|
return data.data.consumption;
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,27 @@
|
|||||||
|
import { Typography } from "@mui/material";
|
||||||
|
import { CurrConsumptionWidget } from "./HomeRoute/CurrConsumptionWidget";
|
||||||
|
import Grid from "@mui/material/Grid2";
|
||||||
|
import { CachedConsumptionWidget } from "./HomeRoute/CachedConsumptionWidget";
|
||||||
|
|
||||||
export function HomeRoute(): React.ReactElement {
|
export function HomeRoute(): React.ReactElement {
|
||||||
return <>home authenticated todo</>;
|
return (
|
||||||
|
<div style={{ flex: 1, padding: "10px" }}>
|
||||||
|
<Typography component="h2" variant="h6" sx={{ mb: 2 }}>
|
||||||
|
Overview
|
||||||
|
</Typography>
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
spacing={2}
|
||||||
|
columns={12}
|
||||||
|
sx={{ mb: (theme) => theme.spacing(2) }}
|
||||||
|
>
|
||||||
|
<Grid size={{ xs: 12, sm: 6, lg: 3 }}>
|
||||||
|
<CurrConsumptionWidget />
|
||||||
|
</Grid>
|
||||||
|
<Grid size={{ xs: 12, sm: 6, lg: 3 }}>
|
||||||
|
<CachedConsumptionWidget />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { EnergyApi } from "../../api/EnergyApi";
|
||||||
|
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||||
|
import StatCard from "../../widgets/StatCard";
|
||||||
|
|
||||||
|
export function CachedConsumptionWidget(): React.ReactElement {
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
|
const [val, setVal] = React.useState<undefined | number>();
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
try {
|
||||||
|
const s = await EnergyApi.CachedConsumption();
|
||||||
|
setVal(s);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
snackbar("Failed to refresh cached consumption!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
const i = setInterval(() => refresh(), 3000);
|
||||||
|
|
||||||
|
return () => clearInterval(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StatCard
|
||||||
|
title="Cached consumption"
|
||||||
|
data={[]}
|
||||||
|
interval="Current data"
|
||||||
|
trend="neutral"
|
||||||
|
value={val?.toString() ?? "Loading"}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { EnergyApi } from "../../api/EnergyApi";
|
||||||
|
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||||
|
import StatCard from "../../widgets/StatCard";
|
||||||
|
|
||||||
|
export function CurrConsumptionWidget(): React.ReactElement {
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
|
||||||
|
const [val, setVal] = React.useState<undefined | number>();
|
||||||
|
|
||||||
|
const refresh = async () => {
|
||||||
|
try {
|
||||||
|
const s = await EnergyApi.CurrConsumption();
|
||||||
|
setVal(s);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
snackbar("Failed to refresh current consumption!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
refresh();
|
||||||
|
const i = setInterval(() => refresh(), 3000);
|
||||||
|
|
||||||
|
return () => clearInterval(i);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StatCard
|
||||||
|
title="Current consumption"
|
||||||
|
data={[]}
|
||||||
|
interval="Current data"
|
||||||
|
trend="neutral"
|
||||||
|
value={val?.toString() ?? "Loading"}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
128
central_frontend/src/widgets/StatCard.tsx
Normal file
128
central_frontend/src/widgets/StatCard.tsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import { useTheme } from "@mui/material/styles";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
|
import Card from "@mui/material/Card";
|
||||||
|
import CardContent from "@mui/material/CardContent";
|
||||||
|
import Chip from "@mui/material/Chip";
|
||||||
|
import Stack from "@mui/material/Stack";
|
||||||
|
import Typography from "@mui/material/Typography";
|
||||||
|
import { SparkLineChart } from "@mui/x-charts/SparkLineChart";
|
||||||
|
import { areaElementClasses } from "@mui/x-charts/LineChart";
|
||||||
|
|
||||||
|
export type StatCardProps = {
|
||||||
|
title: string;
|
||||||
|
value: string;
|
||||||
|
interval: string;
|
||||||
|
trend: "up" | "down" | "neutral";
|
||||||
|
data: number[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function getDaysInMonth(month: number, year: number) {
|
||||||
|
const date = new Date(year, month, 0);
|
||||||
|
const monthName = date.toLocaleDateString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
});
|
||||||
|
const daysInMonth = date.getDate();
|
||||||
|
const days = [];
|
||||||
|
let i = 1;
|
||||||
|
while (days.length < daysInMonth) {
|
||||||
|
days.push(`${monthName} ${i}`);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
function AreaGradient({ color, id }: { color: string; id: string }) {
|
||||||
|
return (
|
||||||
|
<defs>
|
||||||
|
<linearGradient id={id} x1="50%" y1="0%" x2="50%" y2="100%">
|
||||||
|
<stop offset="0%" stopColor={color} stopOpacity={0.3} />
|
||||||
|
<stop offset="100%" stopColor={color} stopOpacity={0} />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function StatCard({
|
||||||
|
title,
|
||||||
|
value,
|
||||||
|
interval,
|
||||||
|
trend,
|
||||||
|
data,
|
||||||
|
}: StatCardProps) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const daysInWeek = getDaysInMonth(4, 2024);
|
||||||
|
|
||||||
|
const trendColors = {
|
||||||
|
up:
|
||||||
|
theme.palette.mode === "light"
|
||||||
|
? theme.palette.success.main
|
||||||
|
: theme.palette.success.dark,
|
||||||
|
down:
|
||||||
|
theme.palette.mode === "light"
|
||||||
|
? theme.palette.error.main
|
||||||
|
: theme.palette.error.dark,
|
||||||
|
neutral:
|
||||||
|
theme.palette.mode === "light"
|
||||||
|
? theme.palette.grey[400]
|
||||||
|
: theme.palette.grey[700],
|
||||||
|
};
|
||||||
|
|
||||||
|
const labelColors = {
|
||||||
|
up: "success" as const,
|
||||||
|
down: "error" as const,
|
||||||
|
neutral: "default" as const,
|
||||||
|
};
|
||||||
|
|
||||||
|
const color = labelColors[trend];
|
||||||
|
const chartColor = trendColors[trend];
|
||||||
|
const trendValues = { up: "+25%", down: "-25%", neutral: "+5%" };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card variant="outlined" sx={{ height: "100%", flexGrow: 1 }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography component="h2" variant="subtitle2" gutterBottom>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
<Stack
|
||||||
|
direction="column"
|
||||||
|
sx={{ justifyContent: "space-between", flexGrow: "1", gap: 1 }}
|
||||||
|
>
|
||||||
|
<Stack sx={{ justifyContent: "space-between" }}>
|
||||||
|
<Stack
|
||||||
|
direction="row"
|
||||||
|
sx={{ justifyContent: "space-between", alignItems: "center" }}
|
||||||
|
>
|
||||||
|
<Typography variant="h4" component="p">
|
||||||
|
{value}
|
||||||
|
</Typography>
|
||||||
|
<Chip size="small" color={color} label={trendValues[trend]} />
|
||||||
|
</Stack>
|
||||||
|
<Typography variant="caption" sx={{ color: "text.secondary" }}>
|
||||||
|
{interval}
|
||||||
|
</Typography>
|
||||||
|
</Stack>
|
||||||
|
<Box sx={{ width: "100%", height: 50 }}>
|
||||||
|
<SparkLineChart
|
||||||
|
colors={[chartColor]}
|
||||||
|
data={data}
|
||||||
|
area
|
||||||
|
showHighlight
|
||||||
|
showTooltip
|
||||||
|
xAxis={{
|
||||||
|
scaleType: "band",
|
||||||
|
data: daysInWeek, // Use the correct property 'data' for xAxis
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
[`& .${areaElementClasses.root}`]: {
|
||||||
|
fill: `url(#area-gradient-${value})`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AreaGradient color={chartColor} id={`area-gradient-${value}`} />
|
||||||
|
</SparkLineChart>
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user