Add ECharts Integration for Enhanced Data Visualization
- Introduced new components, HistoryEChart and HistoryChartLegend, to replace Recharts with ECharts for improved charting capabilities in the dashboard. - Updated HistoryDisplay and ModelHistoryDisplay components to utilize the new ECharts components, enhancing the overall data visualization experience. - Implemented a custom tooltip for ECharts to provide detailed information on data points, improving user interaction and data insights. - Added a hook, useHistoryLegendOverlay, to manage the visibility of the chart legend based on available space, optimizing the layout for different screen sizes. - Removed unused Recharts imports and related code, streamlining the component structure and improving performance.
This commit is contained in:
parent
364d168678
commit
3c53278e9f
87
bun.lock
87
bun.lock
@ -53,6 +53,8 @@
|
||||
"cross-env": "^10.0.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"dotenv": "^17.2.1",
|
||||
"echarts": "^6.1.0",
|
||||
"echarts-for-react": "^3.0.6",
|
||||
"electron-store": "^11.0.2",
|
||||
"gcode-preview": "^2.18.0",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
@ -70,7 +72,6 @@
|
||||
"react-pdf": "^10.5.0",
|
||||
"react-responsive": "^10.0.1",
|
||||
"react-router-dom": "^7.8.2",
|
||||
"recharts": "^3.8.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"simplebar-react": "^3.3.2",
|
||||
"socket.io-client": "*",
|
||||
@ -603,8 +604,6 @@
|
||||
|
||||
"@rc-component/util": ["@rc-component/util@1.8.1", "", { "dependencies": { "is-mobile": "5.0.0", "react-is": "18.3.1" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-Ku6BzF0Ov5L9U3ewFJZDQ//iWCR2nIkLBBiYSrhxIVl3PqeUqiYP2W8gNI8qoKAFQKZdYcS0+B6+SQTDtv/erw=="],
|
||||
|
||||
"@reduxjs/toolkit": ["@reduxjs/toolkit@2.12.0", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "@standard-schema/utils": "0.3.0", "immer": "11.1.8", "redux": "5.0.1", "redux-thunk": "3.1.0", "reselect": "5.1.1" }, "optionalDependencies": { "react": "19.2.4", "react-redux": "9.3.0" } }, "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw=="],
|
||||
|
||||
"@remirror/core-constants": ["@remirror/core-constants@3.0.0", "", {}, "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg=="],
|
||||
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="],
|
||||
@ -673,10 +672,6 @@
|
||||
|
||||
"@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="],
|
||||
|
||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||
|
||||
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
|
||||
|
||||
"@svgr/babel-plugin-add-jsx-attribute": ["@svgr/babel-plugin-add-jsx-attribute@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g=="],
|
||||
|
||||
"@svgr/babel-plugin-remove-jsx-attribute": ["@svgr/babel-plugin-remove-jsx-attribute@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA=="],
|
||||
@ -883,24 +878,6 @@
|
||||
|
||||
"@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="],
|
||||
|
||||
"@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
|
||||
|
||||
"@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
|
||||
|
||||
"@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="],
|
||||
|
||||
"@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "3.1.3" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
|
||||
|
||||
"@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="],
|
||||
|
||||
"@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "3.0.4" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="],
|
||||
|
||||
"@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "3.1.1" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="],
|
||||
|
||||
"@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="],
|
||||
|
||||
"@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
|
||||
|
||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "2.1.0" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||
|
||||
"@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "1.0.9", "@types/json-schema": "7.0.15" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="],
|
||||
@ -1235,28 +1212,6 @@
|
||||
|
||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||
|
||||
"d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "2.0.3" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
|
||||
|
||||
"d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
|
||||
|
||||
"d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
|
||||
|
||||
"d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="],
|
||||
|
||||
"d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "3.1.0" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
|
||||
|
||||
"d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="],
|
||||
|
||||
"d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "3.2.4", "d3-format": "3.1.2", "d3-interpolate": "3.0.1", "d3-time": "3.1.0", "d3-time-format": "4.1.0" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="],
|
||||
|
||||
"d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="],
|
||||
|
||||
"d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "3.2.4" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="],
|
||||
|
||||
"d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "3.1.0" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
|
||||
|
||||
"d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
|
||||
|
||||
"data-uri-to-buffer": ["data-uri-to-buffer@6.0.2", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="],
|
||||
|
||||
"data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="],
|
||||
@ -1271,8 +1226,6 @@
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
|
||||
|
||||
"decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "2.0.2" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
|
||||
|
||||
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
|
||||
@ -1337,6 +1290,10 @@
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
|
||||
"echarts": ["echarts@6.1.0", "", { "dependencies": { "tslib": "2.3.0", "zrender": "6.1.0" } }, "sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA=="],
|
||||
|
||||
"echarts-for-react": ["echarts-for-react@3.0.6", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "size-sensor": "^1.0.1" }, "peerDependencies": { "echarts": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", "react": "^15.0.0 || >=16.0.0" } }, "sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg=="],
|
||||
|
||||
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||
|
||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
@ -1393,8 +1350,6 @@
|
||||
|
||||
"es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "1.2.7", "is-date-object": "1.1.0", "is-symbol": "1.1.1" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="],
|
||||
|
||||
"es-toolkit": ["es-toolkit@1.47.1", "", {}, "sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q=="],
|
||||
|
||||
"es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="],
|
||||
|
||||
"esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
|
||||
@ -1459,8 +1414,6 @@
|
||||
|
||||
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||
|
||||
"eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
|
||||
|
||||
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "7.0.6", "get-stream": "6.0.1", "human-signals": "2.1.0", "is-stream": "2.0.1", "merge-stream": "2.0.0", "npm-run-path": "4.0.1", "onetime": "5.1.2", "signal-exit": "3.0.7", "strip-final-newline": "2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||
|
||||
"exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="],
|
||||
@ -1643,8 +1596,6 @@
|
||||
|
||||
"image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="],
|
||||
|
||||
"immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="],
|
||||
|
||||
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "1.0.1", "resolve-from": "4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
@ -1661,8 +1612,6 @@
|
||||
|
||||
"internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "hasown": "2.0.2", "side-channel": "1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="],
|
||||
|
||||
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
|
||||
|
||||
"ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="],
|
||||
|
||||
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||
@ -2301,8 +2250,6 @@
|
||||
|
||||
"react-pdf": ["react-pdf@10.5.0", "", { "dependencies": { "clsx": "^2.0.0", "dequal": "^2.0.3", "make-cancellable-promise": "^2.0.0", "make-event-props": "^2.0.0", "merge-refs": "^2.0.0", "pdfjs-dist": "5.4.296", "tiny-invariant": "^1.0.0", "warning": "^4.0.0" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-zGKb6Ph5AYn2OfO4TS8Gg0Go3eW5K/TKy0+0FTm8EwFNbpgbuaWBZoJdYkJt+cRBCkizE9dYvqtMtHRj522Q4w=="],
|
||||
|
||||
"react-redux": ["react-redux@9.3.0", "", { "dependencies": { "@types/use-sync-external-store": "0.0.6", "use-sync-external-store": "1.6.0" }, "optionalDependencies": { "@types/react": "19.2.10", "redux": "5.0.1" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g=="],
|
||||
|
||||
"react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="],
|
||||
|
||||
"react-responsive": ["react-responsive@10.0.1", "", { "dependencies": { "hyphenate-style-name": "1.1.0", "matchmediaquery": "0.4.2", "prop-types": "15.8.1", "shallow-equal": "3.1.0" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-OM5/cRvbtUWEX8le8RCT8scA8y2OPtb0Q/IViEyCEM5FBN8lRrkUOZnu87I88A6njxDldvxG+rLBxWiA7/UM9g=="],
|
||||
@ -2319,12 +2266,6 @@
|
||||
|
||||
"readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
|
||||
|
||||
"recharts": ["recharts@3.8.1", "", { "dependencies": { "@reduxjs/toolkit": "2.12.0", "clsx": "2.1.1", "decimal.js-light": "2.5.1", "es-toolkit": "1.47.1", "eventemitter3": "5.0.4", "immer": "10.2.0", "react-redux": "9.3.0", "reselect": "5.1.1", "tiny-invariant": "1.3.3", "use-sync-external-store": "1.6.0", "victory-vendor": "37.3.6" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4", "react-is": "18.3.1" } }, "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg=="],
|
||||
|
||||
"redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="],
|
||||
|
||||
"redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "5.0.1" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="],
|
||||
|
||||
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "which-builtin-type": "1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
||||
|
||||
"regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-errors": "1.3.0", "get-proto": "1.0.1", "gopd": "1.2.0", "set-function-name": "2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="],
|
||||
@ -2351,8 +2292,6 @@
|
||||
|
||||
"resedit": ["resedit@1.7.2", "", { "dependencies": { "pe-library": "^0.4.1" } }, "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA=="],
|
||||
|
||||
"reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
|
||||
|
||||
"resize-observer-polyfill": ["resize-observer-polyfill@1.5.1", "", {}, "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="],
|
||||
|
||||
"resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "2.16.1", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
|
||||
@ -2463,6 +2402,8 @@
|
||||
|
||||
"simplebar-react": ["simplebar-react@3.3.2", "", { "dependencies": { "simplebar-core": "1.3.2" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-ZsgcQhKLtt5ra0BRIJeApfkTBQCa1vUPA/WXI4HcYReFt+oCEOvdVz6rR/XsGJcKxTlCRPmdGx1uJIUChupo+A=="],
|
||||
|
||||
"size-sensor": ["size-sensor@1.0.3", "", {}, "sha512-+k9mJ2/rQMiRmQUcjn+qznch260leIXY8r4FyYKKyRBO/s5UoeMAHGkCJyE1R/4wrIhTJONfyloY55SkE7ve3A=="],
|
||||
|
||||
"slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
|
||||
|
||||
"smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
|
||||
@ -2697,8 +2638,6 @@
|
||||
|
||||
"vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-stringify-position": "4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="],
|
||||
|
||||
"victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "3.2.2", "@types/d3-ease": "3.0.2", "@types/d3-interpolate": "3.0.4", "@types/d3-scale": "4.0.9", "@types/d3-shape": "3.1.8", "@types/d3-time": "3.0.4", "@types/d3-timer": "3.0.2", "d3-array": "3.2.4", "d3-ease": "3.0.1", "d3-interpolate": "3.0.1", "d3-scale": "4.0.2", "d3-shape": "3.2.0", "d3-time": "3.1.0", "d3-timer": "3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="],
|
||||
|
||||
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "0.27.2", "fdir": "6.5.0", "picomatch": "4.0.3", "postcss": "8.5.6", "rollup": "4.57.1", "tinyglobby": "0.2.15" }, "optionalDependencies": { "@types/node": "25.2.0", "fsevents": "2.3.3", "jiti": "2.6.1", "terser": "5.46.0" }, "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
|
||||
|
||||
"vite-plugin-eslint": ["vite-plugin-eslint@1.8.1", "", { "dependencies": { "@rollup/pluginutils": "4.2.1", "@types/eslint": "8.56.12", "rollup": "2.79.2" }, "peerDependencies": { "eslint": "9.39.2", "vite": "7.3.1" } }, "sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang=="],
|
||||
@ -2771,6 +2710,8 @@
|
||||
|
||||
"zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"zrender": ["zrender@6.1.0", "", { "dependencies": { "tslib": "2.3.0" } }, "sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ=="],
|
||||
|
||||
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
|
||||
"@ant-design/colors/@ant-design/fast-color": ["@ant-design/fast-color@3.0.1", "", {}, "sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw=="],
|
||||
@ -2839,8 +2780,6 @@
|
||||
|
||||
"@rc-component/util/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
||||
|
||||
"@reduxjs/toolkit/immer": ["immer@11.1.8", "", {}, "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA=="],
|
||||
|
||||
"@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"@svgr/core/camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="],
|
||||
@ -2915,6 +2854,8 @@
|
||||
|
||||
"dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="],
|
||||
|
||||
"echarts/tslib": ["tslib@2.3.0", "", {}, "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="],
|
||||
|
||||
"electrobun/three": ["three@0.165.0", "", {}, "sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA=="],
|
||||
|
||||
"electron-packager/fs-extra": ["fs-extra@11.4.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA=="],
|
||||
@ -3027,8 +2968,6 @@
|
||||
|
||||
"readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"recharts/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
|
||||
|
||||
"rollup-plugin-inject/estree-walker": ["estree-walker@0.6.1", "", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="],
|
||||
|
||||
"rollup-pluginutils/estree-walker": ["estree-walker@0.6.1", "", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="],
|
||||
@ -3107,6 +3046,8 @@
|
||||
|
||||
"xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="],
|
||||
|
||||
"zrender/tslib": ["tslib@2.3.0", "", {}, "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
|
||||
|
||||
"@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
||||
|
||||
@ -57,6 +57,8 @@
|
||||
"cross-env": "^10.0.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"dotenv": "^17.2.1",
|
||||
"echarts": "^6.1.0",
|
||||
"echarts-for-react": "^3.0.6",
|
||||
"electron-store": "^11.0.2",
|
||||
"gcode-preview": "^2.18.0",
|
||||
"json-schema-traverse": "^1.0.0",
|
||||
@ -74,7 +76,6 @@
|
||||
"react-pdf": "^10.5.0",
|
||||
"react-responsive": "^10.0.1",
|
||||
"react-router-dom": "^7.8.2",
|
||||
"recharts": "^3.8.1",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"simplebar-react": "^3.3.2",
|
||||
"socket.io-client": "*",
|
||||
|
||||
332
pnpm-lock.yaml
generated
332
pnpm-lock.yaml
generated
@ -160,6 +160,12 @@ importers:
|
||||
dotenv:
|
||||
specifier: ^17.2.1
|
||||
version: 17.2.3
|
||||
echarts:
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0
|
||||
echarts-for-react:
|
||||
specifier: ^3.0.6
|
||||
version: 3.0.6(echarts@6.1.0)(react@19.2.4)
|
||||
electron-store:
|
||||
specifier: ^11.0.2
|
||||
version: 11.0.2
|
||||
@ -211,9 +217,6 @@ importers:
|
||||
react-router-dom:
|
||||
specifier: ^7.8.2
|
||||
version: 7.13.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
recharts:
|
||||
specifier: ^3.8.1
|
||||
version: 3.8.1(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react-is@18.3.1)(react@19.2.4)(redux@5.0.1)
|
||||
remark-gfm:
|
||||
specifier: ^4.0.1
|
||||
version: 4.0.1
|
||||
@ -1613,17 +1616,6 @@ packages:
|
||||
react: '>=18.0.0'
|
||||
react-dom: '>=18.0.0'
|
||||
|
||||
'@reduxjs/toolkit@2.12.0':
|
||||
resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==}
|
||||
peerDependencies:
|
||||
react: ^16.9.0 || ^17.0.0 || ^18 || ^19
|
||||
react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
react-redux:
|
||||
optional: true
|
||||
|
||||
'@remirror/core-constants@3.0.0':
|
||||
resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
|
||||
|
||||
@ -1787,12 +1779,6 @@ packages:
|
||||
'@socket.io/component-emitter@3.1.2':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
'@standard-schema/spec@1.1.0':
|
||||
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
||||
|
||||
'@standard-schema/utils@0.3.0':
|
||||
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
|
||||
|
||||
'@svgr/babel-plugin-add-jsx-attribute@8.0.0':
|
||||
resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==}
|
||||
engines: {node: '>=14'}
|
||||
@ -2257,33 +2243,6 @@ packages:
|
||||
'@types/cacheable-request@6.0.3':
|
||||
resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==}
|
||||
|
||||
'@types/d3-array@3.2.2':
|
||||
resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
|
||||
|
||||
'@types/d3-color@3.1.3':
|
||||
resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
|
||||
|
||||
'@types/d3-ease@3.0.2':
|
||||
resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
|
||||
|
||||
'@types/d3-interpolate@3.0.4':
|
||||
resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
|
||||
|
||||
'@types/d3-path@3.1.1':
|
||||
resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==}
|
||||
|
||||
'@types/d3-scale@4.0.9':
|
||||
resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==}
|
||||
|
||||
'@types/d3-shape@3.1.8':
|
||||
resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==}
|
||||
|
||||
'@types/d3-time@3.0.4':
|
||||
resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
|
||||
|
||||
'@types/d3-timer@3.0.2':
|
||||
resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||
|
||||
@ -3083,50 +3042,6 @@ packages:
|
||||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
d3-array@3.2.4:
|
||||
resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-color@3.1.0:
|
||||
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-ease@3.0.1:
|
||||
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-format@3.1.2:
|
||||
resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-interpolate@3.0.1:
|
||||
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-path@3.1.0:
|
||||
resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-scale@4.0.2:
|
||||
resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-shape@3.2.0:
|
||||
resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-time-format@4.1.0:
|
||||
resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-time@3.1.0:
|
||||
resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
d3-timer@3.0.1:
|
||||
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
data-uri-to-buffer@2.0.2:
|
||||
resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==}
|
||||
|
||||
@ -3178,9 +3093,6 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
decimal.js-light@2.5.1:
|
||||
resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
|
||||
|
||||
decode-named-character-reference@1.3.0:
|
||||
resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==}
|
||||
|
||||
@ -3312,6 +3224,15 @@ packages:
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
echarts-for-react@3.0.6:
|
||||
resolution: {integrity: sha512-4zqLgTGWS3JvkQDXjzkR1k1CHRdpd6by0988TWMJgnvDytegWLbeP/VNZmMa+0VJx2eD7Y632bi2JquXDgiGJg==}
|
||||
peerDependencies:
|
||||
echarts: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
|
||||
react: ^15.0.0 || >=16.0.0
|
||||
|
||||
echarts@6.1.0:
|
||||
resolution: {integrity: sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==}
|
||||
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
@ -3430,9 +3351,6 @@ packages:
|
||||
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-toolkit@1.47.1:
|
||||
resolution: {integrity: sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==}
|
||||
|
||||
es6-error@4.1.1:
|
||||
resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
|
||||
|
||||
@ -3666,9 +3584,6 @@ packages:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
eventemitter3@5.0.4:
|
||||
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
|
||||
|
||||
execa@5.1.1:
|
||||
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||
engines: {node: '>=10'}
|
||||
@ -4093,12 +4008,6 @@ packages:
|
||||
image-q@4.0.0:
|
||||
resolution: {integrity: sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==}
|
||||
|
||||
immer@10.2.0:
|
||||
resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==}
|
||||
|
||||
immer@11.1.8:
|
||||
resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
||||
engines: {node: '>=6'}
|
||||
@ -4128,10 +4037,6 @@ packages:
|
||||
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
internmap@2.0.3:
|
||||
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
ip-address@10.1.0:
|
||||
resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==}
|
||||
engines: {node: '>= 12'}
|
||||
@ -5619,18 +5524,6 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
react-redux@9.3.0:
|
||||
resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==}
|
||||
peerDependencies:
|
||||
'@types/react': ^18.2.25 || ^19
|
||||
react: ^18.0 || ^19
|
||||
redux: ^5.0.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
redux:
|
||||
optional: true
|
||||
|
||||
react-refresh@0.18.0:
|
||||
resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -5678,22 +5571,6 @@ packages:
|
||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
recharts@3.8.1:
|
||||
resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
redux-thunk@3.1.0:
|
||||
resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
|
||||
peerDependencies:
|
||||
redux: ^5.0.0
|
||||
|
||||
redux@5.0.1:
|
||||
resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -5740,9 +5617,6 @@ packages:
|
||||
resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
|
||||
reselect@5.1.1:
|
||||
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
|
||||
|
||||
resize-observer-polyfill@1.5.1:
|
||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||
|
||||
@ -5986,6 +5860,9 @@ packages:
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
size-sensor@1.0.3:
|
||||
resolution: {integrity: sha512-+k9mJ2/rQMiRmQUcjn+qznch260leIXY8r4FyYKKyRBO/s5UoeMAHGkCJyE1R/4wrIhTJONfyloY55SkE7ve3A==}
|
||||
|
||||
slash@3.0.0:
|
||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||
engines: {node: '>=8'}
|
||||
@ -6334,6 +6211,9 @@ packages:
|
||||
tsconfig-paths@3.15.0:
|
||||
resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
|
||||
|
||||
tslib@2.3.0:
|
||||
resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
|
||||
|
||||
tslib@2.8.1:
|
||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||
|
||||
@ -6507,9 +6387,6 @@ packages:
|
||||
vfile@6.0.3:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
victory-vendor@37.3.6:
|
||||
resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
|
||||
|
||||
vite-plugin-eslint@1.8.1:
|
||||
resolution: {integrity: sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==}
|
||||
peerDependencies:
|
||||
@ -6737,6 +6614,9 @@ packages:
|
||||
zod@3.25.76:
|
||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||
|
||||
zrender@6.1.0:
|
||||
resolution: {integrity: sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ==}
|
||||
|
||||
zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
|
||||
@ -8277,18 +8157,6 @@ snapshots:
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
react-is: 18.3.1
|
||||
|
||||
'@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.2.10)(react@19.2.4)(redux@5.0.1))(react@19.2.4)':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
'@standard-schema/utils': 0.3.0
|
||||
immer: 11.1.8
|
||||
redux: 5.0.1
|
||||
redux-thunk: 3.1.0(redux@5.0.1)
|
||||
reselect: 5.1.1
|
||||
optionalDependencies:
|
||||
react: 19.2.4
|
||||
react-redux: 9.3.0(@types/react@19.2.10)(react@19.2.4)(redux@5.0.1)
|
||||
|
||||
'@remirror/core-constants@3.0.0': {}
|
||||
|
||||
'@rolldown/pluginutils@1.0.0-beta.53': {}
|
||||
@ -8396,10 +8264,6 @@ snapshots:
|
||||
|
||||
'@socket.io/component-emitter@3.1.2': {}
|
||||
|
||||
'@standard-schema/spec@1.1.0': {}
|
||||
|
||||
'@standard-schema/utils@0.3.0': {}
|
||||
|
||||
'@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.0)':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
@ -8941,30 +8805,6 @@ snapshots:
|
||||
'@types/node': 22.19.7
|
||||
'@types/responselike': 1.0.3
|
||||
|
||||
'@types/d3-array@3.2.2': {}
|
||||
|
||||
'@types/d3-color@3.1.3': {}
|
||||
|
||||
'@types/d3-ease@3.0.2': {}
|
||||
|
||||
'@types/d3-interpolate@3.0.4':
|
||||
dependencies:
|
||||
'@types/d3-color': 3.1.3
|
||||
|
||||
'@types/d3-path@3.1.1': {}
|
||||
|
||||
'@types/d3-scale@4.0.9':
|
||||
dependencies:
|
||||
'@types/d3-time': 3.0.4
|
||||
|
||||
'@types/d3-shape@3.1.8':
|
||||
dependencies:
|
||||
'@types/d3-path': 3.1.1
|
||||
|
||||
'@types/d3-time@3.0.4': {}
|
||||
|
||||
'@types/d3-timer@3.0.2': {}
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
dependencies:
|
||||
'@types/ms': 2.1.0
|
||||
@ -9934,44 +9774,6 @@ snapshots:
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
d3-array@3.2.4:
|
||||
dependencies:
|
||||
internmap: 2.0.3
|
||||
|
||||
d3-color@3.1.0: {}
|
||||
|
||||
d3-ease@3.0.1: {}
|
||||
|
||||
d3-format@3.1.2: {}
|
||||
|
||||
d3-interpolate@3.0.1:
|
||||
dependencies:
|
||||
d3-color: 3.1.0
|
||||
|
||||
d3-path@3.1.0: {}
|
||||
|
||||
d3-scale@4.0.2:
|
||||
dependencies:
|
||||
d3-array: 3.2.4
|
||||
d3-format: 3.1.2
|
||||
d3-interpolate: 3.0.1
|
||||
d3-time: 3.1.0
|
||||
d3-time-format: 4.1.0
|
||||
|
||||
d3-shape@3.2.0:
|
||||
dependencies:
|
||||
d3-path: 3.1.0
|
||||
|
||||
d3-time-format@4.1.0:
|
||||
dependencies:
|
||||
d3-time: 3.1.0
|
||||
|
||||
d3-time@3.1.0:
|
||||
dependencies:
|
||||
d3-array: 3.2.4
|
||||
|
||||
d3-timer@3.0.1: {}
|
||||
|
||||
data-uri-to-buffer@2.0.2: {}
|
||||
|
||||
data-uri-to-buffer@6.0.2: {}
|
||||
@ -10012,8 +9814,6 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
decimal.js-light@2.5.1: {}
|
||||
|
||||
decode-named-character-reference@1.3.0:
|
||||
dependencies:
|
||||
character-entities: 2.0.2
|
||||
@ -10161,6 +9961,18 @@ snapshots:
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
echarts-for-react@3.0.6(echarts@6.1.0)(react@19.2.4):
|
||||
dependencies:
|
||||
echarts: 6.1.0
|
||||
fast-deep-equal: 3.1.3
|
||||
react: 19.2.4
|
||||
size-sensor: 1.0.3
|
||||
|
||||
echarts@6.1.0:
|
||||
dependencies:
|
||||
tslib: 2.3.0
|
||||
zrender: 6.1.0
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
ejs@3.1.10:
|
||||
@ -10409,8 +10221,6 @@ snapshots:
|
||||
is-date-object: 1.1.0
|
||||
is-symbol: 1.1.1
|
||||
|
||||
es-toolkit@1.47.1: {}
|
||||
|
||||
es6-error@4.1.1:
|
||||
optional: true
|
||||
|
||||
@ -10775,8 +10585,6 @@ snapshots:
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
eventemitter3@5.0.4: {}
|
||||
|
||||
execa@5.1.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
@ -11316,10 +11124,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/node': 16.9.1
|
||||
|
||||
immer@10.2.0: {}
|
||||
|
||||
immer@11.1.8: {}
|
||||
|
||||
import-fresh@3.3.1:
|
||||
dependencies:
|
||||
parent-module: 1.0.1
|
||||
@ -11346,8 +11150,6 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
side-channel: 1.1.0
|
||||
|
||||
internmap@2.0.3: {}
|
||||
|
||||
ip-address@10.1.0: {}
|
||||
|
||||
ipaddr.js@1.9.1: {}
|
||||
@ -13207,15 +13009,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.10
|
||||
|
||||
react-redux@9.3.0(@types/react@19.2.10)(react@19.2.4)(redux@5.0.1):
|
||||
dependencies:
|
||||
'@types/use-sync-external-store': 0.0.6
|
||||
react: 19.2.4
|
||||
use-sync-external-store: 1.6.0(react@19.2.4)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.10
|
||||
redux: 5.0.1
|
||||
|
||||
react-refresh@0.18.0: {}
|
||||
|
||||
react-responsive@10.0.1(react@19.2.4):
|
||||
@ -13265,32 +13058,6 @@ snapshots:
|
||||
string_decoder: 1.3.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
recharts@3.8.1(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react-is@18.3.1)(react@19.2.4)(redux@5.0.1):
|
||||
dependencies:
|
||||
'@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.10)(react@19.2.4)(redux@5.0.1))(react@19.2.4)
|
||||
clsx: 2.1.1
|
||||
decimal.js-light: 2.5.1
|
||||
es-toolkit: 1.47.1
|
||||
eventemitter3: 5.0.4
|
||||
immer: 10.2.0
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
react-is: 18.3.1
|
||||
react-redux: 9.3.0(@types/react@19.2.10)(react@19.2.4)(redux@5.0.1)
|
||||
reselect: 5.1.1
|
||||
tiny-invariant: 1.3.3
|
||||
use-sync-external-store: 1.6.0(react@19.2.4)
|
||||
victory-vendor: 37.3.6
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
- redux
|
||||
|
||||
redux-thunk@3.1.0(redux@5.0.1):
|
||||
dependencies:
|
||||
redux: 5.0.1
|
||||
|
||||
redux@5.0.1: {}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
@ -13366,8 +13133,6 @@ snapshots:
|
||||
dependencies:
|
||||
pe-library: 0.4.1
|
||||
|
||||
reselect@5.1.1: {}
|
||||
|
||||
resize-observer-polyfill@1.5.1: {}
|
||||
|
||||
resolve-alpn@1.2.1: {}
|
||||
@ -13713,6 +13478,8 @@ snapshots:
|
||||
react: 19.2.4
|
||||
simplebar-core: 1.3.2
|
||||
|
||||
size-sensor@1.0.3: {}
|
||||
|
||||
slash@3.0.0: {}
|
||||
|
||||
slice-ansi@3.0.0:
|
||||
@ -14114,6 +13881,8 @@ snapshots:
|
||||
minimist: 1.2.8
|
||||
strip-bom: 3.0.0
|
||||
|
||||
tslib@2.3.0: {}
|
||||
|
||||
tslib@2.8.1: {}
|
||||
|
||||
tsparticles@3.9.1:
|
||||
@ -14323,23 +14092,6 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
victory-vendor@37.3.6:
|
||||
dependencies:
|
||||
'@types/d3-array': 3.2.2
|
||||
'@types/d3-ease': 3.0.2
|
||||
'@types/d3-interpolate': 3.0.4
|
||||
'@types/d3-scale': 4.0.9
|
||||
'@types/d3-shape': 3.1.8
|
||||
'@types/d3-time': 3.0.4
|
||||
'@types/d3-timer': 3.0.2
|
||||
d3-array: 3.2.4
|
||||
d3-ease: 3.0.1
|
||||
d3-interpolate: 3.0.1
|
||||
d3-scale: 4.0.2
|
||||
d3-shape: 3.2.0
|
||||
d3-time: 3.1.0
|
||||
d3-timer: 3.0.1
|
||||
|
||||
vite-plugin-eslint@1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.1(@types/node@25.2.0)(jiti@2.6.1)(terser@5.46.0)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 4.2.1
|
||||
@ -14560,4 +14312,8 @@ snapshots:
|
||||
|
||||
zod@3.25.76: {}
|
||||
|
||||
zrender@6.1.0:
|
||||
dependencies:
|
||||
tslib: 2.3.0
|
||||
|
||||
zwitch@2.0.4: {}
|
||||
|
||||
49
src/components/Dashboard/common/HistoryChartLegend.jsx
Normal file
49
src/components/Dashboard/common/HistoryChartLegend.jsx
Normal file
@ -0,0 +1,49 @@
|
||||
import { Flex } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const HistoryChartLegend = ({ seriesLabels, isDarkMode, wrap = true }) => {
|
||||
if (!seriesLabels?.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const textColor = isDarkMode ? '#d9d9d9' : '#595959'
|
||||
|
||||
return (
|
||||
<Flex
|
||||
gap='middle'
|
||||
align='center'
|
||||
wrap={wrap ? 'wrap' : 'nowrap'}
|
||||
justify='center'
|
||||
>
|
||||
{seriesLabels.map(({ label, color }) => (
|
||||
<Flex key={label} gap={6} align='center'>
|
||||
<span
|
||||
style={{
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 2,
|
||||
backgroundColor: color,
|
||||
flexShrink: 0
|
||||
}}
|
||||
/>
|
||||
<span style={{ color: textColor, fontSize: 14, lineHeight: 1 }}>
|
||||
{label}
|
||||
</span>
|
||||
</Flex>
|
||||
))}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
HistoryChartLegend.propTypes = {
|
||||
seriesLabels: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
label: PropTypes.string.isRequired,
|
||||
color: PropTypes.string.isRequired
|
||||
})
|
||||
).isRequired,
|
||||
isDarkMode: PropTypes.bool,
|
||||
wrap: PropTypes.bool
|
||||
}
|
||||
|
||||
export default HistoryChartLegend
|
||||
@ -1,22 +1,12 @@
|
||||
import { useMemo, useState } from 'react'
|
||||
import { Card, Segmented, Flex, Popover, DatePicker, Button, Space } from 'antd'
|
||||
import {
|
||||
ResponsiveContainer,
|
||||
BarChart,
|
||||
Bar,
|
||||
LineChart,
|
||||
Line,
|
||||
CartesianGrid,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Tooltip,
|
||||
Legend
|
||||
} from 'recharts'
|
||||
|
||||
import PropTypes from 'prop-types'
|
||||
import dayjs from 'dayjs'
|
||||
import { useThemeContext } from '../context/ThemeContext'
|
||||
import MissingPlaceholder from './MissingPlaceholder'
|
||||
import HistoryEChart from './HistoryEChart'
|
||||
import HistoryChartLegend from './HistoryChartLegend'
|
||||
import { useHistoryLegendOverlay } from '../hooks/useHistoryLegendOverlay'
|
||||
import CheckIcon from '../../Icons/CheckIcon'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
@ -88,6 +78,19 @@ const getNestedValue = (obj, path) => {
|
||||
return value
|
||||
}
|
||||
|
||||
const legendMeasureStyle = {
|
||||
position: 'absolute',
|
||||
visibility: 'hidden',
|
||||
pointerEvents: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
width: 'max-content',
|
||||
height: 0,
|
||||
overflow: 'hidden'
|
||||
}
|
||||
|
||||
const toCssHeight = (value) =>
|
||||
typeof value === 'number' ? `${value}px` : value
|
||||
|
||||
const HistoryDisplay = ({
|
||||
loading = false,
|
||||
history = [],
|
||||
@ -169,31 +172,45 @@ const HistoryDisplay = ({
|
||||
.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp))
|
||||
}, [history, config, defaultStartDate, defaultEndDate])
|
||||
|
||||
const themeColors = getColors()
|
||||
|
||||
const seriesLabels = useMemo(() => {
|
||||
if (!config) {
|
||||
return []
|
||||
}
|
||||
|
||||
const colors = {
|
||||
success: themeColors.colorSuccess,
|
||||
processing: themeColors.colorInfo,
|
||||
error: themeColors.colorError,
|
||||
warning: themeColors.colorWarning,
|
||||
default: '#8c8c8c',
|
||||
cyan: themeColors.colorCyan,
|
||||
pink: themeColors.colorPink,
|
||||
purple: themeColors.colorPurple,
|
||||
magenta: themeColors.colorMagenta,
|
||||
volcano: themeColors.colorVolcano
|
||||
}
|
||||
|
||||
return config.series.map((seriesDef) => {
|
||||
const color = seriesDef.color
|
||||
? colors[seriesDef.color] || seriesDef.color
|
||||
: colors.default
|
||||
|
||||
return {
|
||||
label: seriesDef.label,
|
||||
color
|
||||
}
|
||||
})
|
||||
}, [config, themeColors])
|
||||
|
||||
const { slotRef, measureRef, overlay: legendOverflow } =
|
||||
useHistoryLegendOverlay(seriesLabels)
|
||||
|
||||
if (!objectType || !config) {
|
||||
return null
|
||||
}
|
||||
|
||||
const themeColors = getColors()
|
||||
const colors = {
|
||||
success: themeColors.colorSuccess,
|
||||
processing: themeColors.colorInfo,
|
||||
error: themeColors.colorError,
|
||||
warning: themeColors.colorWarning,
|
||||
default: '#8c8c8c',
|
||||
cyan: themeColors.colorCyan,
|
||||
pink: themeColors.colorPink,
|
||||
purple: themeColors.colorPurple,
|
||||
magenta: themeColors.colorMagenta,
|
||||
volcano: themeColors.colorVolcano
|
||||
}
|
||||
|
||||
const colorRange = config.series.map((seriesDef) => {
|
||||
if (seriesDef.color) {
|
||||
return colors[seriesDef.color] || seriesDef.color
|
||||
}
|
||||
return colors.default
|
||||
})
|
||||
|
||||
const formatTooltipValue = (value, seriesLabel) => {
|
||||
const seriesDef = config.series.find((item) => item.label === seriesLabel)
|
||||
const suffix = seriesDef?.suffix || unit || ''
|
||||
@ -227,80 +244,15 @@ const HistoryDisplay = ({
|
||||
</Space.Compact>
|
||||
)
|
||||
|
||||
const chartProps = {
|
||||
data: chartRows
|
||||
}
|
||||
|
||||
const axisTickStyle = {
|
||||
fill: isDarkMode ? '#d9d9d9' : '#595959',
|
||||
fontSize: 12
|
||||
}
|
||||
|
||||
const tooltipStyle = {
|
||||
backgroundColor: isDarkMode ? '#1f1f1f' : '#ffffff',
|
||||
border: `1px solid ${isDarkMode ? '#303030' : '#f0f0f0'}`,
|
||||
borderRadius: 8
|
||||
}
|
||||
|
||||
const renderChart = () => {
|
||||
const commonElements = (
|
||||
<>
|
||||
<CartesianGrid
|
||||
strokeDasharray='3 3'
|
||||
stroke={isDarkMode ? '#303030' : '#f0f0f0'}
|
||||
/>
|
||||
<XAxis dataKey='dateFormatted' tick={axisTickStyle} />
|
||||
<YAxis tick={axisTickStyle} />
|
||||
<Tooltip
|
||||
contentStyle={tooltipStyle}
|
||||
formatter={(value, name) => [formatTooltipValue(value, name), name]}
|
||||
/>
|
||||
<Legend />
|
||||
</>
|
||||
)
|
||||
|
||||
if (chartType === 'line') {
|
||||
return (
|
||||
<LineChart {...chartProps}>
|
||||
{commonElements}
|
||||
{config.series.map((seriesDef, index) => (
|
||||
<Line
|
||||
key={seriesDef.label}
|
||||
type='monotone'
|
||||
dataKey={seriesDef.label}
|
||||
stroke={colorRange[index] || colors.default}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
))}
|
||||
</LineChart>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<BarChart {...chartProps}>
|
||||
{commonElements}
|
||||
{config.series.map((seriesDef, index) => (
|
||||
<Bar
|
||||
key={seriesDef.label}
|
||||
dataKey={seriesDef.label}
|
||||
stackId='history'
|
||||
fill={colorRange[index] || colors.default}
|
||||
/>
|
||||
))}
|
||||
</BarChart>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
style={{ width: '100%' }}
|
||||
styles={{ body: { padding: '12px', ...styles } }}
|
||||
>
|
||||
<Flex gap='small' vertical>
|
||||
{!startDate && !endDate && (
|
||||
<Flex justify='space-between'>
|
||||
<Flex align='center' gap='5px'>
|
||||
<Flex style={{ width: '100%' }} justify='space-between' align='center'>
|
||||
<Flex align='center' gap='5px' justify='flex-start'>
|
||||
{!startDate && !endDate && (
|
||||
<Popover
|
||||
content={customTimeRangeContent}
|
||||
trigger='hover'
|
||||
@ -316,45 +268,99 @@ const HistoryDisplay = ({
|
||||
disabled={loading}
|
||||
/>
|
||||
</Popover>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Flex gap='middle'>
|
||||
{loading == true && <LoadingOutlined />}
|
||||
<Segmented
|
||||
size='small'
|
||||
options={[
|
||||
{ label: '24hr', value: '24hrs' },
|
||||
{ label: '12hr', value: '12hrs' },
|
||||
{ label: '8hr', value: '8hrs' },
|
||||
{ label: '4hr', value: '4hrs' },
|
||||
{ label: '1hr', value: '1hrs' },
|
||||
{ label: '30m', value: '30mins' },
|
||||
{ label: '15m', value: '15mins' },
|
||||
{ label: '5m', value: '5mins' }
|
||||
]}
|
||||
value={timeRange}
|
||||
onChange={setTimeRange}
|
||||
disabled={loading}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
{chartRows.length > 0 && (
|
||||
<div style={{ width: '100%', height: `${height}px` }}>
|
||||
<ResponsiveContainer width='100%' height='100%'>
|
||||
{renderChart()}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
)}
|
||||
{loading == false && chartRows.length == 0 && (
|
||||
<Flex
|
||||
justify='center'
|
||||
align='center'
|
||||
style={{ height: `${height}px` }}
|
||||
<div
|
||||
ref={slotRef}
|
||||
style={{
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
<MissingPlaceholder message='No data available.' />
|
||||
{!legendOverflow && (
|
||||
<HistoryChartLegend
|
||||
seriesLabels={seriesLabels}
|
||||
isDarkMode={isDarkMode}
|
||||
/>
|
||||
)}
|
||||
<div ref={measureRef} aria-hidden='true' style={legendMeasureStyle}>
|
||||
<HistoryChartLegend
|
||||
seriesLabels={seriesLabels}
|
||||
isDarkMode={isDarkMode}
|
||||
wrap={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Flex gap='middle' align='center' justify='flex-end'>
|
||||
{!startDate && !endDate && (
|
||||
<>
|
||||
{loading == true && <LoadingOutlined />}
|
||||
<Segmented
|
||||
size='small'
|
||||
options={[
|
||||
{ label: '24hr', value: '24hrs' },
|
||||
{ label: '12hr', value: '12hrs' },
|
||||
{ label: '8hr', value: '8hrs' },
|
||||
{ label: '4hr', value: '4hrs' },
|
||||
{ label: '1hr', value: '1hrs' },
|
||||
{ label: '30m', value: '30mins' },
|
||||
{ label: '15m', value: '15mins' },
|
||||
{ label: '5m', value: '5mins' }
|
||||
]}
|
||||
value={timeRange}
|
||||
onChange={setTimeRange}
|
||||
disabled={loading}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
<div
|
||||
style={{
|
||||
height: toCssHeight(height),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minHeight: 0
|
||||
}}
|
||||
>
|
||||
{legendOverflow && (
|
||||
<div
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
paddingBottom: 4
|
||||
}}
|
||||
>
|
||||
<HistoryChartLegend
|
||||
seriesLabels={seriesLabels}
|
||||
isDarkMode={isDarkMode}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ flex: 1, minHeight: 0 }}>
|
||||
{chartRows.length > 0 && (
|
||||
<HistoryEChart
|
||||
chartRows={chartRows}
|
||||
seriesLabels={seriesLabels}
|
||||
chartType={chartType}
|
||||
isDarkMode={isDarkMode}
|
||||
formatTooltipValue={formatTooltipValue}
|
||||
/>
|
||||
)}
|
||||
{loading == false && chartRows.length == 0 && (
|
||||
<Flex justify='center' align='center' style={{ height: '100%' }}>
|
||||
<MissingPlaceholder message='No data available.' />
|
||||
</Flex>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Flex>
|
||||
</Card>
|
||||
)
|
||||
|
||||
253
src/components/Dashboard/common/HistoryEChart.jsx
Normal file
253
src/components/Dashboard/common/HistoryEChart.jsx
Normal file
@ -0,0 +1,253 @@
|
||||
import { useCallback, useEffect, useId, useMemo, useRef } from 'react'
|
||||
import { Divider, Flex } from 'antd'
|
||||
import ReactECharts from 'echarts-for-react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { useTooltipContext } from '../context/TooltipContext'
|
||||
|
||||
const toCssHeight = (height) => {
|
||||
if (height == null) {
|
||||
return '100%'
|
||||
}
|
||||
|
||||
if (typeof height === 'number') {
|
||||
return `${height}px`
|
||||
}
|
||||
|
||||
return /^\d+$/.test(height) ? `${height}px` : height
|
||||
}
|
||||
|
||||
const getTooltipDataIndex = (params) => {
|
||||
if (params.dataIndex != null) {
|
||||
return params.dataIndex
|
||||
}
|
||||
|
||||
return (
|
||||
params.dataByCoordSys?.[0]?.dataByAxis?.[0]?.seriesDataIndices?.[0]
|
||||
?.dataIndex ?? null
|
||||
)
|
||||
}
|
||||
|
||||
const HistoryChartTooltipContent = ({ header, items }) => (
|
||||
<Flex gap={0} vertical style={{ margin: '3px 1px 1px 1px' }}>
|
||||
<strong>{header}</strong>
|
||||
<Divider style={{ margin: '3px 0 4px 0' }} />
|
||||
<table
|
||||
style={{
|
||||
borderCollapse: 'collapse',
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
<tbody>
|
||||
{items.map(({ label, color, value }) => (
|
||||
<tr key={label}>
|
||||
<td
|
||||
style={{
|
||||
padding: '1px 6px 1px 0',
|
||||
verticalAlign: 'middle',
|
||||
width: 10
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
display: 'block',
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 2,
|
||||
backgroundColor: color
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
padding: '1px 16px 1px 0',
|
||||
verticalAlign: 'middle',
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
padding: '1px 0',
|
||||
verticalAlign: 'middle',
|
||||
textAlign: 'right',
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
<strong>{value}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</Flex>
|
||||
)
|
||||
|
||||
HistoryChartTooltipContent.propTypes = {
|
||||
header: PropTypes.string.isRequired,
|
||||
items: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
label: PropTypes.string.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||
.isRequired
|
||||
})
|
||||
).isRequired
|
||||
}
|
||||
|
||||
const HistoryEChart = ({
|
||||
chartRows,
|
||||
seriesLabels,
|
||||
chartType = 'bar',
|
||||
isDarkMode,
|
||||
height,
|
||||
formatTooltipValue
|
||||
}) => {
|
||||
const chartRef = useRef(null)
|
||||
const tooltipId = useId()
|
||||
const { showTooltip, hideTooltip } = useTooltipContext()
|
||||
|
||||
useEffect(() => () => hideTooltip(tooltipId), [hideTooltip, tooltipId])
|
||||
|
||||
const handleShowTip = useCallback(
|
||||
(params) => {
|
||||
const dataIndex = getTooltipDataIndex(params)
|
||||
if (dataIndex == null) {
|
||||
return
|
||||
}
|
||||
|
||||
const row = chartRows[dataIndex]
|
||||
if (!row) {
|
||||
return
|
||||
}
|
||||
|
||||
const chart = chartRef.current?.getEchartsInstance()
|
||||
const dom = chart?.getDom()
|
||||
if (!dom || params.x == null || params.y == null) {
|
||||
return
|
||||
}
|
||||
|
||||
const rect = dom.getBoundingClientRect()
|
||||
const items = seriesLabels.map(({ label, color }) => ({
|
||||
label,
|
||||
color,
|
||||
value: formatTooltipValue
|
||||
? formatTooltipValue(row[label], label)
|
||||
: row[label]
|
||||
}))
|
||||
|
||||
showTooltip(
|
||||
tooltipId,
|
||||
<HistoryChartTooltipContent header={row.dateFormatted} items={items} />,
|
||||
rect.left + params.x,
|
||||
rect.top + params.y
|
||||
)
|
||||
},
|
||||
[chartRows, seriesLabels, formatTooltipValue, showTooltip, tooltipId]
|
||||
)
|
||||
|
||||
const handleHideTip = useCallback(() => {
|
||||
hideTooltip(tooltipId)
|
||||
}, [hideTooltip, tooltipId])
|
||||
|
||||
const onEvents = useMemo(
|
||||
() => ({
|
||||
showTip: handleShowTip,
|
||||
hideTip: handleHideTip,
|
||||
globalout: handleHideTip
|
||||
}),
|
||||
[handleShowTip, handleHideTip]
|
||||
)
|
||||
|
||||
const option = useMemo(() => {
|
||||
const axisColor = isDarkMode ? '#d9d9d9' : '#595959'
|
||||
const gridColor = isDarkMode ? '#303030' : '#f0f0f0'
|
||||
|
||||
const categories = chartRows.map((row) => row.dateFormatted)
|
||||
|
||||
return {
|
||||
textStyle: {
|
||||
fontFamily: "'DM Sans', sans-serif"
|
||||
},
|
||||
grid: {
|
||||
left: 8,
|
||||
right: 8,
|
||||
top: 8,
|
||||
bottom: 8,
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
showContent: false,
|
||||
axisPointer: {
|
||||
type: chartType === 'line' ? 'line' : 'shadow'
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: categories,
|
||||
axisLabel: {
|
||||
color: axisColor,
|
||||
fontSize: 12
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: { color: gridColor }
|
||||
},
|
||||
axisTick: {
|
||||
lineStyle: { color: gridColor }
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
color: axisColor,
|
||||
fontSize: 12
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: gridColor,
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: seriesLabels.map(({ label, color }) => ({
|
||||
name: label,
|
||||
type: chartType,
|
||||
stack: chartType === 'bar' ? 'history' : undefined,
|
||||
smooth: chartType === 'line',
|
||||
showSymbol: false,
|
||||
emphasis: { focus: 'series' },
|
||||
itemStyle: { color },
|
||||
lineStyle: chartType === 'line' ? { width: 2, color } : undefined,
|
||||
data: chartRows.map((row) => row[label] ?? 0)
|
||||
}))
|
||||
}
|
||||
}, [chartRows, seriesLabels, chartType, isDarkMode])
|
||||
|
||||
return (
|
||||
<ReactECharts
|
||||
ref={chartRef}
|
||||
option={option}
|
||||
style={{ width: '100%', height: toCssHeight(height) }}
|
||||
onEvents={onEvents}
|
||||
notMerge
|
||||
lazyUpdate
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
HistoryEChart.propTypes = {
|
||||
chartRows: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
seriesLabels: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
label: PropTypes.string.isRequired,
|
||||
color: PropTypes.string.isRequired
|
||||
})
|
||||
).isRequired,
|
||||
chartType: PropTypes.oneOf(['line', 'bar']),
|
||||
isDarkMode: PropTypes.bool,
|
||||
height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
formatTooltipValue: PropTypes.func
|
||||
}
|
||||
|
||||
export default HistoryEChart
|
||||
@ -9,19 +9,6 @@ import {
|
||||
Space,
|
||||
Switch
|
||||
} from 'antd'
|
||||
import {
|
||||
ResponsiveContainer,
|
||||
BarChart,
|
||||
Bar,
|
||||
LineChart,
|
||||
Line,
|
||||
CartesianGrid,
|
||||
XAxis,
|
||||
YAxis,
|
||||
Tooltip,
|
||||
Legend
|
||||
} from 'recharts'
|
||||
|
||||
import PropTypes from 'prop-types'
|
||||
import { getModelByName } from '../../../database/ObjectModels'
|
||||
import { ApiServerContext } from '../context/ApiServerContext'
|
||||
@ -29,9 +16,25 @@ import { AuthContext } from '../context/AuthContext'
|
||||
import dayjs from 'dayjs'
|
||||
import { useThemeContext } from '../context/ThemeContext'
|
||||
import MissingPlaceholder from './MissingPlaceholder'
|
||||
import HistoryEChart from './HistoryEChart'
|
||||
import HistoryChartLegend from './HistoryChartLegend'
|
||||
import { useHistoryLegendOverlay } from '../hooks/useHistoryLegendOverlay'
|
||||
import CheckIcon from '../../Icons/CheckIcon'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
|
||||
const legendMeasureStyle = {
|
||||
position: 'absolute',
|
||||
visibility: 'hidden',
|
||||
pointerEvents: 'none',
|
||||
whiteSpace: 'nowrap',
|
||||
width: 'max-content',
|
||||
height: 0,
|
||||
overflow: 'hidden'
|
||||
}
|
||||
|
||||
const toCssHeight = (value) =>
|
||||
typeof value === 'number' ? `${value}px` : value
|
||||
|
||||
const ModelHistoryDisplay = ({
|
||||
objectType,
|
||||
startDate,
|
||||
@ -123,20 +126,55 @@ const ModelHistoryDisplay = ({
|
||||
defaultEndDate
|
||||
])
|
||||
|
||||
const model = useMemo(
|
||||
() => (objectType ? getModelByName(objectType) : null),
|
||||
[objectType]
|
||||
)
|
||||
|
||||
const modelStats = useMemo(
|
||||
() => (model?.stats || []).filter((statDef) => statDef.history !== false),
|
||||
[model]
|
||||
)
|
||||
|
||||
const themeColors = getColors()
|
||||
|
||||
const seriesLabels = useMemo(() => {
|
||||
const colors = {
|
||||
success: themeColors.colorSuccess,
|
||||
processing: themeColors.colorInfo,
|
||||
error: themeColors.colorError,
|
||||
warning: themeColors.colorWarning,
|
||||
default: '#8c8c8c',
|
||||
cyan: themeColors.colorCyan,
|
||||
pink: themeColors.colorPink,
|
||||
purple: themeColors.colorPurple,
|
||||
magenta: themeColors.colorMagenta,
|
||||
volcano: themeColors.colorVolcano
|
||||
}
|
||||
|
||||
return modelStats.map((statDef) => {
|
||||
const color = statDef.color
|
||||
? colors[statDef.color] || statDef.color
|
||||
: colors.default
|
||||
|
||||
return {
|
||||
label: statDef.label || statDef.name,
|
||||
color
|
||||
}
|
||||
})
|
||||
}, [modelStats, themeColors])
|
||||
|
||||
const { slotRef, measureRef, overlay: legendOverflow } =
|
||||
useHistoryLegendOverlay(seriesLabels)
|
||||
|
||||
if (!objectType) {
|
||||
return null
|
||||
}
|
||||
|
||||
const model = getModelByName(objectType)
|
||||
|
||||
if (!model) {
|
||||
return null
|
||||
}
|
||||
|
||||
const modelStats = (model.stats || []).filter(
|
||||
(statDef) => statDef.history !== false
|
||||
)
|
||||
|
||||
if (modelStats.length === 0) {
|
||||
return null
|
||||
}
|
||||
@ -273,30 +311,6 @@ const ModelHistoryDisplay = ({
|
||||
return new Date(a.date) - new Date(b.date)
|
||||
})
|
||||
|
||||
const themeColors = getColors()
|
||||
|
||||
// Create color mapping from model stats
|
||||
const colors = {
|
||||
success: themeColors.colorSuccess,
|
||||
processing: themeColors.colorInfo,
|
||||
error: themeColors.colorError,
|
||||
warning: themeColors.colorWarning,
|
||||
default: '#8c8c8c',
|
||||
cyan: themeColors.colorCyan,
|
||||
pink: themeColors.colorPink,
|
||||
purple: themeColors.colorPurple,
|
||||
magenta: themeColors.colorMagenta,
|
||||
volcano: themeColors.colorVolcano
|
||||
}
|
||||
|
||||
// Build color range array based on model stats order
|
||||
const colorRange = modelStats.map((stat) => {
|
||||
if (stat.color) {
|
||||
return colors[stat.color] || stat.color
|
||||
}
|
||||
return colors.default
|
||||
})
|
||||
|
||||
const absoluteRows = Array.from(
|
||||
chartData
|
||||
.reduce((acc, item) => {
|
||||
@ -354,78 +368,14 @@ const ModelHistoryDisplay = ({
|
||||
</Space.Compact>
|
||||
)
|
||||
|
||||
const axisTickStyle = {
|
||||
fill: isDarkMode ? '#d9d9d9' : '#595959',
|
||||
fontSize: 12
|
||||
}
|
||||
|
||||
const tooltipStyle = {
|
||||
backgroundColor: isDarkMode ? '#1f1f1f' : '#ffffff',
|
||||
border: `1px solid ${isDarkMode ? '#303030' : '#f0f0f0'}`,
|
||||
borderRadius: 8
|
||||
}
|
||||
|
||||
const renderChart = () => {
|
||||
const commonElements = (
|
||||
<>
|
||||
<CartesianGrid
|
||||
strokeDasharray='3 3'
|
||||
stroke={isDarkMode ? '#303030' : '#f0f0f0'}
|
||||
/>
|
||||
<XAxis dataKey='dateFormatted' tick={axisTickStyle} />
|
||||
<YAxis tick={axisTickStyle} />
|
||||
<Tooltip contentStyle={tooltipStyle} />
|
||||
<Legend />
|
||||
</>
|
||||
)
|
||||
|
||||
if (chartType === 'line') {
|
||||
return (
|
||||
<LineChart data={chartRows}>
|
||||
{commonElements}
|
||||
{modelStats.map((statDef, index) => {
|
||||
const category = statDef.label || statDef.name
|
||||
return (
|
||||
<Line
|
||||
key={category}
|
||||
type='monotone'
|
||||
dataKey={category}
|
||||
stroke={colorRange[index] || colors.default}
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</LineChart>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<BarChart data={chartRows}>
|
||||
{commonElements}
|
||||
{modelStats.map((statDef, index) => {
|
||||
const category = statDef.label || statDef.name
|
||||
return (
|
||||
<Bar
|
||||
key={category}
|
||||
dataKey={category}
|
||||
stackId='history'
|
||||
fill={colorRange[index] || colors.default}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</BarChart>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
style={{ width: '100%' }}
|
||||
styles={{ body: { padding: '12px', ...styles } }}
|
||||
>
|
||||
<Flex gap='small' vertical>
|
||||
<Flex justify='space-between' align='center'>
|
||||
<Flex align='center' gap='small'>
|
||||
<Flex style={{ width: '100%' }} justify='space-between' align='center'>
|
||||
<Flex align='center' gap='5px' justify='flex-start'>
|
||||
{!startDate && !endDate && (
|
||||
<Popover
|
||||
content={customTimeRangeContent}
|
||||
@ -455,50 +405,97 @@ const ModelHistoryDisplay = ({
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
{!startDate && !endDate && (
|
||||
<Flex gap='middle' align='center'>
|
||||
{loading == true && chartRows.length != 0 && <LoadingOutlined />}
|
||||
<Segmented
|
||||
size='small'
|
||||
options={[
|
||||
{ label: '24hr', value: '24hrs' },
|
||||
{ label: '12hr', value: '12hrs' },
|
||||
{ label: '8hr', value: '8hrs' },
|
||||
{ label: '4hr', value: '4hrs' },
|
||||
{ label: '1hr', value: '1hrs' }
|
||||
]}
|
||||
value={timeRange}
|
||||
onChange={setTimeRange}
|
||||
disabled={loading}
|
||||
<div
|
||||
ref={slotRef}
|
||||
style={{
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
{!legendOverflow && (
|
||||
<HistoryChartLegend
|
||||
seriesLabels={seriesLabels}
|
||||
isDarkMode={isDarkMode}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
{chartRows.length > 0 && (
|
||||
<div style={{ width: '100%', height: `${height}px` }}>
|
||||
<ResponsiveContainer width='100%' height='100%'>
|
||||
{renderChart()}
|
||||
</ResponsiveContainer>
|
||||
)}
|
||||
<div ref={measureRef} aria-hidden='true' style={legendMeasureStyle}>
|
||||
<HistoryChartLegend
|
||||
seriesLabels={seriesLabels}
|
||||
isDarkMode={isDarkMode}
|
||||
wrap={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{loading == true && chartRows.length == 0 && (
|
||||
<Flex
|
||||
justify='center'
|
||||
align='center'
|
||||
style={{ height: `${height}px` }}
|
||||
>
|
||||
<LoadingOutlined />
|
||||
|
||||
<Flex gap='middle' align='center' justify='flex-end'>
|
||||
{!startDate && !endDate && (
|
||||
<>
|
||||
{loading == true && chartRows.length != 0 && <LoadingOutlined />}
|
||||
<Segmented
|
||||
size='small'
|
||||
options={[
|
||||
{ label: '24hr', value: '24hrs' },
|
||||
{ label: '12hr', value: '12hrs' },
|
||||
{ label: '8hr', value: '8hrs' },
|
||||
{ label: '4hr', value: '4hrs' },
|
||||
{ label: '1hr', value: '1hrs' }
|
||||
]}
|
||||
value={timeRange}
|
||||
onChange={setTimeRange}
|
||||
disabled={loading}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
{loading == false && chartRows.length == 0 && (
|
||||
<Flex
|
||||
justify='center'
|
||||
align='center'
|
||||
style={{ height: `${height}px` }}
|
||||
>
|
||||
<MissingPlaceholder message='No data available.' />
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
<div
|
||||
style={{
|
||||
height: toCssHeight(height),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minHeight: 0
|
||||
}}
|
||||
>
|
||||
{legendOverflow && (
|
||||
<div
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
paddingBottom: 4
|
||||
}}
|
||||
>
|
||||
<HistoryChartLegend
|
||||
seriesLabels={seriesLabels}
|
||||
isDarkMode={isDarkMode}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div style={{ flex: 1, minHeight: 0 }}>
|
||||
{chartRows.length > 0 && (
|
||||
<HistoryEChart
|
||||
chartRows={chartRows}
|
||||
seriesLabels={seriesLabels}
|
||||
chartType={chartType}
|
||||
isDarkMode={isDarkMode}
|
||||
/>
|
||||
)}
|
||||
{loading == true && chartRows.length == 0 && (
|
||||
<Flex justify='center' align='center' style={{ height: '100%' }}>
|
||||
<LoadingOutlined />
|
||||
</Flex>
|
||||
)}
|
||||
{loading == false && chartRows.length == 0 && (
|
||||
<Flex justify='center' align='center' style={{ height: '100%' }}>
|
||||
<MissingPlaceholder message='No data available.' />
|
||||
</Flex>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Flex>
|
||||
</Card>
|
||||
)
|
||||
|
||||
43
src/components/Dashboard/hooks/useHistoryLegendOverlay.js
Normal file
43
src/components/Dashboard/hooks/useHistoryLegendOverlay.js
Normal file
@ -0,0 +1,43 @@
|
||||
import { useLayoutEffect, useRef, useState } from 'react'
|
||||
|
||||
export const useHistoryLegendOverlay = (seriesLabels) => {
|
||||
const slotRef = useRef(null)
|
||||
const measureRef = useRef(null)
|
||||
const [overlay, setOverlay] = useState(false)
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const slot = slotRef.current
|
||||
const measure = measureRef.current
|
||||
if (!slot || !measure) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
const availableWidth = slot.getBoundingClientRect().width
|
||||
if (availableWidth < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
const naturalWidth = measure.scrollWidth
|
||||
const shouldOverlay = naturalWidth > availableWidth + 1
|
||||
|
||||
setOverlay((previous) =>
|
||||
previous === shouldOverlay ? previous : shouldOverlay
|
||||
)
|
||||
}
|
||||
|
||||
update()
|
||||
const frame = requestAnimationFrame(update)
|
||||
|
||||
const resizeObserver = new ResizeObserver(update)
|
||||
resizeObserver.observe(slot)
|
||||
resizeObserver.observe(measure)
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(frame)
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}, [seriesLabels])
|
||||
|
||||
return { slotRef, measureRef, overlay }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user