feat: implement RAG dashboard with MUI and react-router
Add new RAG dashboard feature including: - Main application layout with header and sidebar - Multiple pages (Home, KnowledgeBase, PipelineConfig, Dashboard, MCP) - Theme configuration and styling - Routing setup with protected routes - Login page and authentication flow - Various UI components and mock data for dashboard views
This commit is contained in:
@@ -10,8 +10,14 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.14.0",
|
||||||
|
"@emotion/styled": "^11.14.1",
|
||||||
|
"@mui/icons-material": "^7.3.4",
|
||||||
|
"@mui/material": "^7.3.4",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^18.3.1",
|
||||||
|
"react-is": "18.3.1",
|
||||||
|
"react-router-dom": "^7.9.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.36.0",
|
"@eslint/js": "^9.36.0",
|
||||||
|
|||||||
602
pnpm-lock.yaml
generated
602
pnpm-lock.yaml
generated
@@ -8,12 +8,30 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@emotion/react':
|
||||||
|
specifier: ^11.14.0
|
||||||
|
version: 11.14.0(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@emotion/styled':
|
||||||
|
specifier: ^11.14.1
|
||||||
|
version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@mui/icons-material':
|
||||||
|
specifier: ^7.3.4
|
||||||
|
version: 7.3.4(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@mui/material':
|
||||||
|
specifier: ^7.3.4
|
||||||
|
version: 7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
react:
|
react:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
react-dom:
|
react-dom:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1(react@18.3.1)
|
version: 18.3.1(react@18.3.1)
|
||||||
|
react-is:
|
||||||
|
specifier: 18.3.1
|
||||||
|
version: 18.3.1
|
||||||
|
react-router-dom:
|
||||||
|
specifier: ^7.9.4
|
||||||
|
version: 7.9.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@eslint/js':
|
'@eslint/js':
|
||||||
specifier: ^9.36.0
|
specifier: ^9.36.0
|
||||||
@@ -125,6 +143,10 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@babel/core': ^7.0.0-0
|
'@babel/core': ^7.0.0-0
|
||||||
|
|
||||||
|
'@babel/runtime@7.28.4':
|
||||||
|
resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@babel/template@7.27.2':
|
'@babel/template@7.27.2':
|
||||||
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -137,6 +159,60 @@ packages:
|
|||||||
resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
|
resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@emotion/babel-plugin@11.13.5':
|
||||||
|
resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
|
||||||
|
|
||||||
|
'@emotion/cache@11.14.0':
|
||||||
|
resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==}
|
||||||
|
|
||||||
|
'@emotion/hash@0.9.2':
|
||||||
|
resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==}
|
||||||
|
|
||||||
|
'@emotion/is-prop-valid@1.4.0':
|
||||||
|
resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==}
|
||||||
|
|
||||||
|
'@emotion/memoize@0.9.0':
|
||||||
|
resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
|
||||||
|
|
||||||
|
'@emotion/react@11.14.0':
|
||||||
|
resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
react: '>=16.8.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@emotion/serialize@1.3.3':
|
||||||
|
resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==}
|
||||||
|
|
||||||
|
'@emotion/sheet@1.4.0':
|
||||||
|
resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==}
|
||||||
|
|
||||||
|
'@emotion/styled@11.14.1':
|
||||||
|
resolution: {integrity: sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.0.0-rc.0
|
||||||
|
'@types/react': '*'
|
||||||
|
react: '>=16.8.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@emotion/unitless@0.10.0':
|
||||||
|
resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==}
|
||||||
|
|
||||||
|
'@emotion/use-insertion-effect-with-fallbacks@1.2.0':
|
||||||
|
resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8.0'
|
||||||
|
|
||||||
|
'@emotion/utils@1.4.2':
|
||||||
|
resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==}
|
||||||
|
|
||||||
|
'@emotion/weak-memoize@0.4.0':
|
||||||
|
resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.10':
|
'@esbuild/aix-ppc64@0.25.10':
|
||||||
resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==}
|
resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -363,6 +439,97 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.31':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
|
'@mui/core-downloads-tracker@7.3.4':
|
||||||
|
resolution: {integrity: sha512-BIktMapG3r4iXwIhYNpvk97ZfYWTreBBQTWjQKbNbzI64+ULHfYavQEX2w99aSWHS58DvXESWIgbD9adKcUOBw==}
|
||||||
|
|
||||||
|
'@mui/icons-material@7.3.4':
|
||||||
|
resolution: {integrity: sha512-9n6Xcq7molXWYb680N2Qx+FRW8oT6j/LXF5PZFH3ph9X/Rct0B/BlLAsFI7iL9ySI6LVLuQIVtrLiPT82R7OZw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@mui/material': ^7.3.4
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@mui/material@7.3.4':
|
||||||
|
resolution: {integrity: sha512-gEQL9pbJZZHT7lYJBKQCS723v1MGys2IFc94COXbUIyCTWa+qC77a7hUax4Yjd5ggEm35dk4AyYABpKKWC4MLw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.5.0
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
'@mui/material-pigment-css': ^7.3.3
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
'@mui/material-pigment-css':
|
||||||
|
optional: true
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@mui/private-theming@7.3.3':
|
||||||
|
resolution: {integrity: sha512-OJM+9nj5JIyPUvsZ5ZjaeC9PfktmK+W5YaVLToLR8L0lB/DGmv1gcKE43ssNLSvpoW71Hct0necfade6+kW3zQ==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@mui/styled-engine@7.3.3':
|
||||||
|
resolution: {integrity: sha512-CmFxvRJIBCEaWdilhXMw/5wFJ1+FT9f3xt+m2pPXhHPeVIbBg9MnMvNSJjdALvnQJMPw8jLhrUtXmN7QAZV2fw==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.4.1
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@mui/system@7.3.3':
|
||||||
|
resolution: {integrity: sha512-Lqq3emZr5IzRLKaHPuMaLBDVaGvxoh6z7HMWd1RPKawBM5uMRaQ4ImsmmgXWtwJdfZux5eugfDhXJUo2mliS8Q==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.5.0
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@mui/types@7.4.7':
|
||||||
|
resolution: {integrity: sha512-8vVje9rdEr1rY8oIkYgP+Su5Kwl6ik7O3jQ0wl78JGSmiZhRHV+vkjooGdKD8pbtZbutXFVTWQYshu2b3sG9zw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@mui/utils@7.3.3':
|
||||||
|
resolution: {integrity: sha512-kwNAUh7bLZ7mRz9JZ+6qfRnnxbE4Zuc+RzXnhSpRSxjTlSTj7b4JxRLXpG+MVtPVtqks5k/XC8No1Vs3x4Z2gg==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -375,6 +542,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
'@popperjs/core@2.11.8':
|
||||||
|
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||||
|
|
||||||
'@rolldown/pluginutils@1.0.0-beta.38':
|
'@rolldown/pluginutils@1.0.0-beta.38':
|
||||||
resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==}
|
resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==}
|
||||||
|
|
||||||
@@ -509,11 +679,22 @@ packages:
|
|||||||
'@types/node@24.7.0':
|
'@types/node@24.7.0':
|
||||||
resolution: {integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==}
|
resolution: {integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==}
|
||||||
|
|
||||||
|
'@types/parse-json@4.0.2':
|
||||||
|
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||||
|
|
||||||
|
'@types/prop-types@15.7.15':
|
||||||
|
resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
|
||||||
|
|
||||||
'@types/react-dom@19.2.1':
|
'@types/react-dom@19.2.1':
|
||||||
resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==}
|
resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^19.2.0
|
'@types/react': ^19.2.0
|
||||||
|
|
||||||
|
'@types/react-transition-group@4.4.12':
|
||||||
|
resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
|
||||||
'@types/react@19.2.2':
|
'@types/react@19.2.2':
|
||||||
resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==}
|
resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==}
|
||||||
|
|
||||||
@@ -602,6 +783,10 @@ packages:
|
|||||||
argparse@2.0.1:
|
argparse@2.0.1:
|
||||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||||
|
|
||||||
|
babel-plugin-macros@3.1.0:
|
||||||
|
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
|
||||||
|
engines: {node: '>=10', npm: '>=6'}
|
||||||
|
|
||||||
balanced-match@1.0.2:
|
balanced-match@1.0.2:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
|
|
||||||
@@ -635,6 +820,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
clsx@2.1.1:
|
||||||
|
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
engines: {node: '>=7.0.0'}
|
engines: {node: '>=7.0.0'}
|
||||||
@@ -645,9 +834,20 @@ packages:
|
|||||||
concat-map@0.0.1:
|
concat-map@0.0.1:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
|
|
||||||
|
convert-source-map@1.9.0:
|
||||||
|
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
|
||||||
|
|
||||||
convert-source-map@2.0.0:
|
convert-source-map@2.0.0:
|
||||||
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
|
||||||
|
|
||||||
|
cookie@1.0.2:
|
||||||
|
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
cosmiconfig@7.1.0:
|
||||||
|
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -667,9 +867,15 @@ packages:
|
|||||||
deep-is@0.1.4:
|
deep-is@0.1.4:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
|
|
||||||
|
dom-helpers@5.2.1:
|
||||||
|
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
||||||
|
|
||||||
electron-to-chromium@1.5.233:
|
electron-to-chromium@1.5.233:
|
||||||
resolution: {integrity: sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==}
|
resolution: {integrity: sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==}
|
||||||
|
|
||||||
|
error-ex@1.3.4:
|
||||||
|
resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
|
||||||
|
|
||||||
esbuild@0.25.10:
|
esbuild@0.25.10:
|
||||||
resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==}
|
resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -769,6 +975,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
find-root@1.1.0:
|
||||||
|
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
|
||||||
|
|
||||||
find-up@5.0.0:
|
find-up@5.0.0:
|
||||||
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -785,6 +994,9 @@ packages:
|
|||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
|
function-bind@1.1.2:
|
||||||
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
gensync@1.0.0-beta.2:
|
gensync@1.0.0-beta.2:
|
||||||
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -812,6 +1024,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
hoist-non-react-statics@3.3.2:
|
||||||
|
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||||
|
|
||||||
ignore@5.3.2:
|
ignore@5.3.2:
|
||||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
@@ -828,6 +1047,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
||||||
engines: {node: '>=0.8.19'}
|
engines: {node: '>=0.8.19'}
|
||||||
|
|
||||||
|
is-arrayish@0.2.1:
|
||||||
|
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||||
|
|
||||||
|
is-core-module@2.16.1:
|
||||||
|
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-extglob@2.1.1:
|
is-extglob@2.1.1:
|
||||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -858,6 +1084,9 @@ packages:
|
|||||||
json-buffer@3.0.1:
|
json-buffer@3.0.1:
|
||||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||||
|
|
||||||
|
json-parse-even-better-errors@2.3.1:
|
||||||
|
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||||
|
|
||||||
json-schema-traverse@0.4.1:
|
json-schema-traverse@0.4.1:
|
||||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||||
|
|
||||||
@@ -876,6 +1105,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
|
lines-and-columns@1.2.4:
|
||||||
|
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -919,6 +1151,10 @@ packages:
|
|||||||
node-releases@2.0.23:
|
node-releases@2.0.23:
|
||||||
resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==}
|
resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==}
|
||||||
|
|
||||||
|
object-assign@4.1.1:
|
||||||
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
optionator@0.9.4:
|
optionator@0.9.4:
|
||||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@@ -935,6 +1171,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
parse-json@5.2.0:
|
||||||
|
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
path-exists@4.0.0:
|
path-exists@4.0.0:
|
||||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -943,6 +1183,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
path-parse@1.0.7:
|
||||||
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||||
|
|
||||||
|
path-type@4.0.0:
|
||||||
|
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
picocolors@1.1.1:
|
picocolors@1.1.1:
|
||||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
@@ -962,6 +1209,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
|
prop-types@15.8.1:
|
||||||
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
|
|
||||||
punycode@2.3.1:
|
punycode@2.3.1:
|
||||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -974,10 +1224,42 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^18.3.1
|
react: ^18.3.1
|
||||||
|
|
||||||
|
react-is@16.13.1:
|
||||||
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
|
|
||||||
|
react-is@18.3.1:
|
||||||
|
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
|
||||||
|
|
||||||
|
react-is@19.2.0:
|
||||||
|
resolution: {integrity: sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==}
|
||||||
|
|
||||||
react-refresh@0.17.0:
|
react-refresh@0.17.0:
|
||||||
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
|
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
react-router-dom@7.9.4:
|
||||||
|
resolution: {integrity: sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=18'
|
||||||
|
react-dom: '>=18'
|
||||||
|
|
||||||
|
react-router@7.9.4:
|
||||||
|
resolution: {integrity: sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==}
|
||||||
|
engines: {node: '>=20.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=18'
|
||||||
|
react-dom: '>=18'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
react-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
react-transition-group@4.4.5:
|
||||||
|
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.6.0'
|
||||||
|
react-dom: '>=16.6.0'
|
||||||
|
|
||||||
react@18.3.1:
|
react@18.3.1:
|
||||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -986,6 +1268,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
resolve@1.22.10:
|
||||||
|
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
reusify@1.1.0:
|
reusify@1.1.0:
|
||||||
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||||
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||||
@@ -1010,6 +1297,9 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
set-cookie-parser@2.7.1:
|
||||||
|
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -1022,14 +1312,25 @@ packages:
|
|||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
source-map@0.5.7:
|
||||||
|
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
strip-json-comments@3.1.1:
|
strip-json-comments@3.1.1:
|
||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
stylis@4.2.0:
|
||||||
|
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@1.0.0:
|
||||||
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
tinyglobby@0.2.15:
|
tinyglobby@0.2.15:
|
||||||
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -1124,6 +1425,10 @@ packages:
|
|||||||
yallist@3.1.1:
|
yallist@3.1.1:
|
||||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||||
|
|
||||||
|
yaml@1.10.2:
|
||||||
|
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
yocto-queue@0.1.0:
|
yocto-queue@0.1.0:
|
||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -1219,6 +1524,8 @@ snapshots:
|
|||||||
'@babel/core': 7.28.4
|
'@babel/core': 7.28.4
|
||||||
'@babel/helper-plugin-utils': 7.27.1
|
'@babel/helper-plugin-utils': 7.27.1
|
||||||
|
|
||||||
|
'@babel/runtime@7.28.4': {}
|
||||||
|
|
||||||
'@babel/template@7.27.2':
|
'@babel/template@7.27.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.27.1
|
'@babel/code-frame': 7.27.1
|
||||||
@@ -1242,6 +1549,89 @@ snapshots:
|
|||||||
'@babel/helper-string-parser': 7.27.1
|
'@babel/helper-string-parser': 7.27.1
|
||||||
'@babel/helper-validator-identifier': 7.27.1
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
|
|
||||||
|
'@emotion/babel-plugin@11.13.5':
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-module-imports': 7.27.1
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@emotion/hash': 0.9.2
|
||||||
|
'@emotion/memoize': 0.9.0
|
||||||
|
'@emotion/serialize': 1.3.3
|
||||||
|
babel-plugin-macros: 3.1.0
|
||||||
|
convert-source-map: 1.9.0
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
find-root: 1.1.0
|
||||||
|
source-map: 0.5.7
|
||||||
|
stylis: 4.2.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@emotion/cache@11.14.0':
|
||||||
|
dependencies:
|
||||||
|
'@emotion/memoize': 0.9.0
|
||||||
|
'@emotion/sheet': 1.4.0
|
||||||
|
'@emotion/utils': 1.4.2
|
||||||
|
'@emotion/weak-memoize': 0.4.0
|
||||||
|
stylis: 4.2.0
|
||||||
|
|
||||||
|
'@emotion/hash@0.9.2': {}
|
||||||
|
|
||||||
|
'@emotion/is-prop-valid@1.4.0':
|
||||||
|
dependencies:
|
||||||
|
'@emotion/memoize': 0.9.0
|
||||||
|
|
||||||
|
'@emotion/memoize@0.9.0': {}
|
||||||
|
|
||||||
|
'@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@emotion/babel-plugin': 11.13.5
|
||||||
|
'@emotion/cache': 11.14.0
|
||||||
|
'@emotion/serialize': 1.3.3
|
||||||
|
'@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1)
|
||||||
|
'@emotion/utils': 1.4.2
|
||||||
|
'@emotion/weak-memoize': 0.4.0
|
||||||
|
hoist-non-react-statics: 3.3.2
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@emotion/serialize@1.3.3':
|
||||||
|
dependencies:
|
||||||
|
'@emotion/hash': 0.9.2
|
||||||
|
'@emotion/memoize': 0.9.0
|
||||||
|
'@emotion/unitless': 0.10.0
|
||||||
|
'@emotion/utils': 1.4.2
|
||||||
|
csstype: 3.1.3
|
||||||
|
|
||||||
|
'@emotion/sheet@1.4.0': {}
|
||||||
|
|
||||||
|
'@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@emotion/babel-plugin': 11.13.5
|
||||||
|
'@emotion/is-prop-valid': 1.4.0
|
||||||
|
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@emotion/serialize': 1.3.3
|
||||||
|
'@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1)
|
||||||
|
'@emotion/utils': 1.4.2
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@emotion/unitless@0.10.0': {}
|
||||||
|
|
||||||
|
'@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
react: 18.3.1
|
||||||
|
|
||||||
|
'@emotion/utils@1.4.2': {}
|
||||||
|
|
||||||
|
'@emotion/weak-memoize@0.4.0': {}
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.10':
|
'@esbuild/aix-ppc64@0.25.10':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -1396,6 +1786,93 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@mui/core-downloads-tracker@7.3.4': {}
|
||||||
|
|
||||||
|
'@mui/icons-material@7.3.4(@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@mui/material': 7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
|
'@mui/material@7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@mui/core-downloads-tracker': 7.3.4
|
||||||
|
'@mui/system': 7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@mui/types': 7.4.7(@types/react@19.2.2)
|
||||||
|
'@mui/utils': 7.3.3(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@popperjs/core': 2.11.8
|
||||||
|
'@types/react-transition-group': 4.4.12(@types/react@19.2.2)
|
||||||
|
clsx: 2.1.1
|
||||||
|
csstype: 3.1.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-is: 19.2.0
|
||||||
|
react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
optionalDependencies:
|
||||||
|
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
|
'@mui/private-theming@7.3.3(@types/react@19.2.2)(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@mui/utils': 7.3.3(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
|
'@mui/styled-engine@7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@emotion/cache': 11.14.0
|
||||||
|
'@emotion/serialize': 1.3.3
|
||||||
|
'@emotion/sheet': 1.4.0
|
||||||
|
csstype: 3.1.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
|
||||||
|
'@mui/system@7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@mui/private-theming': 7.3.3(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@mui/styled-engine': 7.3.3(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1))(react@18.3.1)
|
||||||
|
'@mui/types': 7.4.7(@types/react@19.2.2)
|
||||||
|
'@mui/utils': 7.3.3(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
clsx: 2.1.1
|
||||||
|
csstype: 3.1.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
'@emotion/react': 11.14.0(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@18.3.1))(@types/react@19.2.2)(react@18.3.1)
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
|
'@mui/types@7.4.7(@types/react@19.2.2)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
|
'@mui/utils@7.3.3(@types/react@19.2.2)(react@18.3.1)':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
'@mui/types': 7.4.7(@types/react@19.2.2)
|
||||||
|
'@types/prop-types': 15.7.15
|
||||||
|
clsx: 2.1.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-is: 19.2.0
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
@@ -1408,6 +1885,8 @@ snapshots:
|
|||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.19.1
|
fastq: 1.19.1
|
||||||
|
|
||||||
|
'@popperjs/core@2.11.8': {}
|
||||||
|
|
||||||
'@rolldown/pluginutils@1.0.0-beta.38': {}
|
'@rolldown/pluginutils@1.0.0-beta.38': {}
|
||||||
|
|
||||||
'@rollup/rollup-android-arm-eabi@4.52.4':
|
'@rollup/rollup-android-arm-eabi@4.52.4':
|
||||||
@@ -1505,10 +1984,18 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.14.0
|
undici-types: 7.14.0
|
||||||
|
|
||||||
|
'@types/parse-json@4.0.2': {}
|
||||||
|
|
||||||
|
'@types/prop-types@15.7.15': {}
|
||||||
|
|
||||||
'@types/react-dom@19.2.1(@types/react@19.2.2)':
|
'@types/react-dom@19.2.1(@types/react@19.2.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 19.2.2
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
|
'@types/react-transition-group@4.4.12(@types/react@19.2.2)':
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 19.2.2
|
||||||
|
|
||||||
'@types/react@19.2.2':
|
'@types/react@19.2.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
@@ -1637,6 +2124,12 @@ snapshots:
|
|||||||
|
|
||||||
argparse@2.0.1: {}
|
argparse@2.0.1: {}
|
||||||
|
|
||||||
|
babel-plugin-macros@3.1.0:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
cosmiconfig: 7.1.0
|
||||||
|
resolve: 1.22.10
|
||||||
|
|
||||||
balanced-match@1.0.2: {}
|
balanced-match@1.0.2: {}
|
||||||
|
|
||||||
baseline-browser-mapping@2.8.14: {}
|
baseline-browser-mapping@2.8.14: {}
|
||||||
@@ -1671,6 +2164,8 @@ snapshots:
|
|||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
supports-color: 7.2.0
|
supports-color: 7.2.0
|
||||||
|
|
||||||
|
clsx@2.1.1: {}
|
||||||
|
|
||||||
color-convert@2.0.1:
|
color-convert@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.4
|
color-name: 1.1.4
|
||||||
@@ -1679,8 +2174,20 @@ snapshots:
|
|||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
|
|
||||||
|
convert-source-map@1.9.0: {}
|
||||||
|
|
||||||
convert-source-map@2.0.0: {}
|
convert-source-map@2.0.0: {}
|
||||||
|
|
||||||
|
cookie@1.0.2: {}
|
||||||
|
|
||||||
|
cosmiconfig@7.1.0:
|
||||||
|
dependencies:
|
||||||
|
'@types/parse-json': 4.0.2
|
||||||
|
import-fresh: 3.3.1
|
||||||
|
parse-json: 5.2.0
|
||||||
|
path-type: 4.0.0
|
||||||
|
yaml: 1.10.2
|
||||||
|
|
||||||
cross-spawn@7.0.6:
|
cross-spawn@7.0.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
@@ -1695,8 +2202,17 @@ snapshots:
|
|||||||
|
|
||||||
deep-is@0.1.4: {}
|
deep-is@0.1.4: {}
|
||||||
|
|
||||||
|
dom-helpers@5.2.1:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
csstype: 3.1.3
|
||||||
|
|
||||||
electron-to-chromium@1.5.233: {}
|
electron-to-chromium@1.5.233: {}
|
||||||
|
|
||||||
|
error-ex@1.3.4:
|
||||||
|
dependencies:
|
||||||
|
is-arrayish: 0.2.1
|
||||||
|
|
||||||
esbuild@0.25.10:
|
esbuild@0.25.10:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/aix-ppc64': 0.25.10
|
'@esbuild/aix-ppc64': 0.25.10
|
||||||
@@ -1835,6 +2351,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range: 5.0.1
|
to-regex-range: 5.0.1
|
||||||
|
|
||||||
|
find-root@1.1.0: {}
|
||||||
|
|
||||||
find-up@5.0.0:
|
find-up@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
locate-path: 6.0.0
|
locate-path: 6.0.0
|
||||||
@@ -1850,6 +2368,8 @@ snapshots:
|
|||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
gensync@1.0.0-beta.2: {}
|
gensync@1.0.0-beta.2: {}
|
||||||
|
|
||||||
glob-parent@5.1.2:
|
glob-parent@5.1.2:
|
||||||
@@ -1868,6 +2388,14 @@ snapshots:
|
|||||||
|
|
||||||
has-flag@4.0.0: {}
|
has-flag@4.0.0: {}
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
dependencies:
|
||||||
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
hoist-non-react-statics@3.3.2:
|
||||||
|
dependencies:
|
||||||
|
react-is: 16.13.1
|
||||||
|
|
||||||
ignore@5.3.2: {}
|
ignore@5.3.2: {}
|
||||||
|
|
||||||
ignore@7.0.5: {}
|
ignore@7.0.5: {}
|
||||||
@@ -1879,6 +2407,12 @@ snapshots:
|
|||||||
|
|
||||||
imurmurhash@0.1.4: {}
|
imurmurhash@0.1.4: {}
|
||||||
|
|
||||||
|
is-arrayish@0.2.1: {}
|
||||||
|
|
||||||
|
is-core-module@2.16.1:
|
||||||
|
dependencies:
|
||||||
|
hasown: 2.0.2
|
||||||
|
|
||||||
is-extglob@2.1.1: {}
|
is-extglob@2.1.1: {}
|
||||||
|
|
||||||
is-glob@4.0.3:
|
is-glob@4.0.3:
|
||||||
@@ -1899,6 +2433,8 @@ snapshots:
|
|||||||
|
|
||||||
json-buffer@3.0.1: {}
|
json-buffer@3.0.1: {}
|
||||||
|
|
||||||
|
json-parse-even-better-errors@2.3.1: {}
|
||||||
|
|
||||||
json-schema-traverse@0.4.1: {}
|
json-schema-traverse@0.4.1: {}
|
||||||
|
|
||||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||||
@@ -1914,6 +2450,8 @@ snapshots:
|
|||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
type-check: 0.4.0
|
type-check: 0.4.0
|
||||||
|
|
||||||
|
lines-and-columns@1.2.4: {}
|
||||||
|
|
||||||
locate-path@6.0.0:
|
locate-path@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate: 5.0.0
|
p-locate: 5.0.0
|
||||||
@@ -1951,6 +2489,8 @@ snapshots:
|
|||||||
|
|
||||||
node-releases@2.0.23: {}
|
node-releases@2.0.23: {}
|
||||||
|
|
||||||
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
optionator@0.9.4:
|
optionator@0.9.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
deep-is: 0.1.4
|
deep-is: 0.1.4
|
||||||
@@ -1972,10 +2512,21 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
callsites: 3.1.0
|
callsites: 3.1.0
|
||||||
|
|
||||||
|
parse-json@5.2.0:
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.27.1
|
||||||
|
error-ex: 1.3.4
|
||||||
|
json-parse-even-better-errors: 2.3.1
|
||||||
|
lines-and-columns: 1.2.4
|
||||||
|
|
||||||
path-exists@4.0.0: {}
|
path-exists@4.0.0: {}
|
||||||
|
|
||||||
path-key@3.1.1: {}
|
path-key@3.1.1: {}
|
||||||
|
|
||||||
|
path-parse@1.0.7: {}
|
||||||
|
|
||||||
|
path-type@4.0.0: {}
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
picomatch@2.3.1: {}
|
picomatch@2.3.1: {}
|
||||||
@@ -1990,6 +2541,12 @@ snapshots:
|
|||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
|
prop-types@15.8.1:
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
react-is: 16.13.1
|
||||||
|
|
||||||
punycode@2.3.1: {}
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
queue-microtask@1.2.3: {}
|
queue-microtask@1.2.3: {}
|
||||||
@@ -2000,14 +2557,49 @@ snapshots:
|
|||||||
react: 18.3.1
|
react: 18.3.1
|
||||||
scheduler: 0.23.2
|
scheduler: 0.23.2
|
||||||
|
|
||||||
|
react-is@16.13.1: {}
|
||||||
|
|
||||||
|
react-is@18.3.1: {}
|
||||||
|
|
||||||
|
react-is@19.2.0: {}
|
||||||
|
|
||||||
react-refresh@0.17.0: {}
|
react-refresh@0.17.0: {}
|
||||||
|
|
||||||
|
react-router-dom@7.9.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
react-router: 7.9.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
||||||
|
react-router@7.9.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
cookie: 1.0.2
|
||||||
|
react: 18.3.1
|
||||||
|
set-cookie-parser: 2.7.1
|
||||||
|
optionalDependencies:
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
|
||||||
|
react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.28.4
|
||||||
|
dom-helpers: 5.2.1
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.3.1
|
||||||
|
react-dom: 18.3.1(react@18.3.1)
|
||||||
|
|
||||||
react@18.3.1:
|
react@18.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
|
|
||||||
resolve-from@4.0.0: {}
|
resolve-from@4.0.0: {}
|
||||||
|
|
||||||
|
resolve@1.22.10:
|
||||||
|
dependencies:
|
||||||
|
is-core-module: 2.16.1
|
||||||
|
path-parse: 1.0.7
|
||||||
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
|
|
||||||
reusify@1.1.0: {}
|
reusify@1.1.0: {}
|
||||||
|
|
||||||
rollup@4.52.4:
|
rollup@4.52.4:
|
||||||
@@ -2050,6 +2642,8 @@ snapshots:
|
|||||||
|
|
||||||
semver@7.7.3: {}
|
semver@7.7.3: {}
|
||||||
|
|
||||||
|
set-cookie-parser@2.7.1: {}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
shebang-regex: 3.0.0
|
shebang-regex: 3.0.0
|
||||||
@@ -2058,12 +2652,18 @@ snapshots:
|
|||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
source-map@0.5.7: {}
|
||||||
|
|
||||||
strip-json-comments@3.1.1: {}
|
strip-json-comments@3.1.1: {}
|
||||||
|
|
||||||
|
stylis@4.2.0: {}
|
||||||
|
|
||||||
supports-color@7.2.0:
|
supports-color@7.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-flag: 4.0.0
|
has-flag: 4.0.0
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
tinyglobby@0.2.15:
|
tinyglobby@0.2.15:
|
||||||
dependencies:
|
dependencies:
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
@@ -2126,4 +2726,6 @@ snapshots:
|
|||||||
|
|
||||||
yallist@3.1.1: {}
|
yallist@3.1.1: {}
|
||||||
|
|
||||||
|
yaml@1.10.2: {}
|
||||||
|
|
||||||
yocto-queue@0.1.0: {}
|
yocto-queue@0.1.0: {}
|
||||||
|
|||||||
42
src/App.tsx
42
src/App.tsx
@@ -1,35 +1,17 @@
|
|||||||
import { useState } from 'react'
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import reactLogo from './assets/react.svg'
|
import { CssBaseline, ThemeProvider } from '@mui/material';
|
||||||
import viteLogo from '/vite.svg'
|
import { theme } from './theme';
|
||||||
import './App.css'
|
import AppRoutes from './routes';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [count, setCount] = useState(0)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<ThemeProvider theme={theme}>
|
||||||
<div>
|
<CssBaseline />
|
||||||
<a href="https://vite.dev" target="_blank">
|
<BrowserRouter>
|
||||||
<img src={viteLogo} className="logo" alt="Vite logo" />
|
<AppRoutes />
|
||||||
</a>
|
</BrowserRouter>
|
||||||
<a href="https://react.dev" target="_blank">
|
</ThemeProvider>
|
||||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
);
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<h1>Vite + React</h1>
|
|
||||||
<div className="card">
|
|
||||||
<button onClick={() => setCount((count) => count + 1)}>
|
|
||||||
count is {count}
|
|
||||||
</button>
|
|
||||||
<p>
|
|
||||||
Edit <code>src/App.tsx</code> and save to test HMR
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<p className="read-the-docs">
|
|
||||||
Click on the Vite and React logos to learn more
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App
|
export default App;
|
||||||
|
|||||||
73
src/components/Layout/Header.tsx
Normal file
73
src/components/Layout/Header.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import { Box, InputBase, styled } from '@mui/material';
|
||||||
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
|
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
|
||||||
|
|
||||||
|
const HeaderContainer = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '0 20px',
|
||||||
|
height: '60px',
|
||||||
|
backgroundColor: '#FFFFFF',
|
||||||
|
color: '#333',
|
||||||
|
boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
|
||||||
|
borderBottom: '1px solid #E5E5E5',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const BrandTitle = styled(Box)(({ theme }) => ({
|
||||||
|
fontSize: '1.2rem',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
color: '#333',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const SearchBox = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: '#F8F9FA',
|
||||||
|
borderRadius: '6px',
|
||||||
|
padding: '6px 12px',
|
||||||
|
width: '320px',
|
||||||
|
border: '1px solid #E5E5E5',
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: '20px',
|
||||||
|
'&:focus-within': {
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
boxShadow: `0 0 0 2px rgba(226,0,116,0.1)`,
|
||||||
|
},
|
||||||
|
'& .MuiInputBase-input': {
|
||||||
|
border: 'none',
|
||||||
|
outline: 'none',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
fontSize: '14px',
|
||||||
|
color: '#333',
|
||||||
|
'&::placeholder': {
|
||||||
|
color: '#999',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const SearchInput = styled(InputBase)(({ theme }) => ({
|
||||||
|
marginLeft: '8px',
|
||||||
|
flex: 1,
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const UserAvatar = styled(AccountCircleIcon)(({ theme }) => ({
|
||||||
|
color: '#666',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontSize: '2rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Header = () => {
|
||||||
|
return (
|
||||||
|
<HeaderContainer>
|
||||||
|
<BrandTitle>RAG Dashboard</BrandTitle>
|
||||||
|
<SearchBox>
|
||||||
|
<SearchIcon sx={{ color: '#999', fontSize: '1.2rem' }} />
|
||||||
|
<SearchInput placeholder="Search queries, KB names..." />
|
||||||
|
</SearchBox>
|
||||||
|
<UserAvatar titleAccess="User Profile" />
|
||||||
|
</HeaderContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
||||||
39
src/components/Layout/MainLayout.tsx
Normal file
39
src/components/Layout/MainLayout.tsx
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { Box, styled } from '@mui/material';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
import Header from './Header';
|
||||||
|
import Sidebar from './Sidebar';
|
||||||
|
|
||||||
|
const LayoutContainer = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
height: '100vh',
|
||||||
|
});
|
||||||
|
|
||||||
|
const MainContent = styled(Box)({
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflow: 'hidden',
|
||||||
|
});
|
||||||
|
|
||||||
|
const ContentArea = styled(Box)({
|
||||||
|
flex: 1,
|
||||||
|
padding: '20px',
|
||||||
|
overflow: 'auto',
|
||||||
|
backgroundColor: '#f5f7fa',
|
||||||
|
});
|
||||||
|
|
||||||
|
const MainLayout = () => {
|
||||||
|
return (
|
||||||
|
<LayoutContainer>
|
||||||
|
<Sidebar />
|
||||||
|
<MainContent>
|
||||||
|
<Header />
|
||||||
|
<ContentArea>
|
||||||
|
<Outlet />
|
||||||
|
</ContentArea>
|
||||||
|
</MainContent>
|
||||||
|
</LayoutContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MainLayout;
|
||||||
73
src/components/Layout/Sidebar.tsx
Normal file
73
src/components/Layout/Sidebar.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import { Box, List, ListItem, ListItemButton, ListItemText, Typography, styled } from '@mui/material';
|
||||||
|
import { Link, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
const SidebarContainer = styled(Box)(({ theme }) => ({
|
||||||
|
width: '240px',
|
||||||
|
backgroundColor: '#1E1E24',
|
||||||
|
color: '#DDD',
|
||||||
|
height: '100vh',
|
||||||
|
padding: '1rem 0',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Logo = styled(Typography)(({ theme }) => ({
|
||||||
|
fontSize: '1.05rem',
|
||||||
|
fontWeight: 600,
|
||||||
|
padding: '0 1.25rem 1rem',
|
||||||
|
margin: '0 0 0.5rem',
|
||||||
|
color: '#FFF',
|
||||||
|
letterSpacing: '0.5px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const NavItem = styled(ListItemButton)<{ active?: boolean }>(({ active, theme }) => ({
|
||||||
|
color: active ? '#FFF' : '#B9B9C2',
|
||||||
|
backgroundColor: active ? 'rgba(226,0,116,0.12)' : 'transparent',
|
||||||
|
borderLeft: active ? `4px solid ${theme.palette.primary.main}` : '4px solid transparent',
|
||||||
|
fontWeight: active ? 600 : 'normal',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.05)',
|
||||||
|
color: '#FFF',
|
||||||
|
},
|
||||||
|
'& .MuiListItemText-primary': {
|
||||||
|
fontSize: '0.9rem',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const Footer = styled(Box)(({ theme }) => ({
|
||||||
|
marginTop: 'auto',
|
||||||
|
padding: '20px',
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
opacity: 0.7,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const navItems = [
|
||||||
|
{ text: 'Overview', path: '/' },
|
||||||
|
{ text: 'Knowledge Bases', path: '/kb-list' },
|
||||||
|
{ text: 'RAG Pipeline', path: '/pipeline-config' },
|
||||||
|
{ text: 'Operations', path: '/dashboard' },
|
||||||
|
{ text: 'Models & Resources', path: '/models-resources' },
|
||||||
|
{ text: 'MCP', path: '/mcp' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const Sidebar = () => {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarContainer>
|
||||||
|
<Logo>RAGflow Prototype</Logo>
|
||||||
|
<List>
|
||||||
|
{navItems.map((item) => (
|
||||||
|
<Link to={item.path} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
|
<NavItem active={location.pathname === item.path}>
|
||||||
|
<ListItemText primary={item.text} />
|
||||||
|
</NavItem>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
<Footer>© 2025 RAG Demo</Footer>
|
||||||
|
</SidebarContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Sidebar;
|
||||||
369
src/pages/Dashboard.tsx
Normal file
369
src/pages/Dashboard.tsx
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Grid,
|
||||||
|
Button,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Paper,
|
||||||
|
Chip,
|
||||||
|
LinearProgress,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
TrendingUp as TrendingUpIcon,
|
||||||
|
TrendingDown as TrendingDownIcon,
|
||||||
|
Assessment as AssessmentIcon,
|
||||||
|
Speed as SpeedIcon,
|
||||||
|
Error as ErrorIcon,
|
||||||
|
CheckCircle as CheckCircleIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const PageContainer = styled(Box)(({ theme }) => ({
|
||||||
|
padding: '1.5rem',
|
||||||
|
backgroundColor: '#F8F9FA',
|
||||||
|
minHeight: 'calc(100vh - 60px)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const PageHeader = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const MetricCard = styled(Card)(({ theme }) => ({
|
||||||
|
height: '100%',
|
||||||
|
border: '1px solid #E5E5E5',
|
||||||
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
'&:hover': {
|
||||||
|
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const MetricValue = styled(Typography)(({ theme }) => ({
|
||||||
|
fontSize: '2rem',
|
||||||
|
fontWeight: 700,
|
||||||
|
lineHeight: 1.2,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const TrendIndicator = styled(Box)<{ trend: 'up' | 'down' }>(({ trend, theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.25rem',
|
||||||
|
color: trend === 'up' ? '#28A745' : '#DC3545',
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
fontWeight: 500,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusChip = styled(Chip)<{ status: string }>(({ status, theme }) => ({
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
height: '24px',
|
||||||
|
backgroundColor:
|
||||||
|
status === 'success' ? '#E8F5E8' :
|
||||||
|
status === 'warning' ? '#FFF3CD' :
|
||||||
|
status === 'error' ? '#F8D7DA' : '#F8F9FA',
|
||||||
|
color:
|
||||||
|
status === 'success' ? '#155724' :
|
||||||
|
status === 'warning' ? '#856404' :
|
||||||
|
status === 'error' ? '#721C24' : '#666',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockMetrics = {
|
||||||
|
totalQueries: { value: 12847, trend: 'up', change: '+12.5%' },
|
||||||
|
avgResponseTime: { value: '2.3s', trend: 'down', change: '-8.2%' },
|
||||||
|
successRate: { value: '98.7%', trend: 'up', change: '+0.3%' },
|
||||||
|
activeUsers: { value: 1256, trend: 'up', change: '+5.7%' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockRecentQueries = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
query: '如何配置RAG Pipeline的参数?',
|
||||||
|
user: 'user@example.com',
|
||||||
|
status: 'success',
|
||||||
|
responseTime: '1.8s',
|
||||||
|
timestamp: '2024-01-15 14:30:25',
|
||||||
|
knowledgeBase: '产品文档库',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
query: '客服系统的常见问题有哪些?',
|
||||||
|
user: 'admin@company.com',
|
||||||
|
status: 'success',
|
||||||
|
responseTime: '2.1s',
|
||||||
|
timestamp: '2024-01-15 14:28:15',
|
||||||
|
knowledgeBase: '客服FAQ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
query: '法律合规要求的详细说明',
|
||||||
|
user: 'legal@company.com',
|
||||||
|
status: 'warning',
|
||||||
|
responseTime: '4.2s',
|
||||||
|
timestamp: '2024-01-15 14:25:10',
|
||||||
|
knowledgeBase: '法律合规',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
query: '员工培训流程和要求',
|
||||||
|
user: 'hr@company.com',
|
||||||
|
status: 'error',
|
||||||
|
responseTime: 'N/A',
|
||||||
|
timestamp: '2024-01-15 14:22:45',
|
||||||
|
knowledgeBase: '培训资料',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Dashboard: React.FC = () => {
|
||||||
|
const [timeRange, setTimeRange] = useState('24h');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<PageHeader>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="#333">
|
||||||
|
运营监控
|
||||||
|
</Typography>
|
||||||
|
<FormControl size="small" sx={{ minWidth: 120 }}>
|
||||||
|
<InputLabel>时间范围</InputLabel>
|
||||||
|
<Select
|
||||||
|
value={timeRange}
|
||||||
|
onChange={(e) => setTimeRange(e.target.value)}
|
||||||
|
label="时间范围"
|
||||||
|
>
|
||||||
|
<MenuItem value="1h">最近1小时</MenuItem>
|
||||||
|
<MenuItem value="24h">最近24小时</MenuItem>
|
||||||
|
<MenuItem value="7d">最近7天</MenuItem>
|
||||||
|
<MenuItem value="30d">最近30天</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
{/* 关键指标卡片 */}
|
||||||
|
<Grid container spacing={3} sx={{ mb: 3 }}>
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<MetricCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
总查询数
|
||||||
|
</Typography>
|
||||||
|
<MetricValue color="primary">
|
||||||
|
{mockMetrics.totalQueries.value.toLocaleString()}
|
||||||
|
</MetricValue>
|
||||||
|
<TrendIndicator trend={mockMetrics.totalQueries.trend}>
|
||||||
|
{mockMetrics.totalQueries.trend === 'up' ?
|
||||||
|
<TrendingUpIcon fontSize="small" /> :
|
||||||
|
<TrendingDownIcon fontSize="small" />
|
||||||
|
}
|
||||||
|
{mockMetrics.totalQueries.change}
|
||||||
|
</TrendIndicator>
|
||||||
|
</Box>
|
||||||
|
<AssessmentIcon color="primary" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</MetricCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<MetricCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
平均响应时间
|
||||||
|
</Typography>
|
||||||
|
<MetricValue color="warning.main">
|
||||||
|
{mockMetrics.avgResponseTime.value}
|
||||||
|
</MetricValue>
|
||||||
|
<TrendIndicator trend={mockMetrics.avgResponseTime.trend}>
|
||||||
|
{mockMetrics.avgResponseTime.trend === 'up' ?
|
||||||
|
<TrendingUpIcon fontSize="small" /> :
|
||||||
|
<TrendingDownIcon fontSize="small" />
|
||||||
|
}
|
||||||
|
{mockMetrics.avgResponseTime.change}
|
||||||
|
</TrendIndicator>
|
||||||
|
</Box>
|
||||||
|
<SpeedIcon color="warning" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</MetricCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<MetricCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
成功率
|
||||||
|
</Typography>
|
||||||
|
<MetricValue color="success.main">
|
||||||
|
{mockMetrics.successRate.value}
|
||||||
|
</MetricValue>
|
||||||
|
<TrendIndicator trend={mockMetrics.successRate.trend}>
|
||||||
|
{mockMetrics.successRate.trend === 'up' ?
|
||||||
|
<TrendingUpIcon fontSize="small" /> :
|
||||||
|
<TrendingDownIcon fontSize="small" />
|
||||||
|
}
|
||||||
|
{mockMetrics.successRate.change}
|
||||||
|
</TrendIndicator>
|
||||||
|
</Box>
|
||||||
|
<CheckCircleIcon color="success" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</MetricCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<MetricCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
活跃用户
|
||||||
|
</Typography>
|
||||||
|
<MetricValue color="info.main">
|
||||||
|
{mockMetrics.activeUsers.value.toLocaleString()}
|
||||||
|
</MetricValue>
|
||||||
|
<TrendIndicator trend={mockMetrics.activeUsers.trend}>
|
||||||
|
{mockMetrics.activeUsers.trend === 'up' ?
|
||||||
|
<TrendingUpIcon fontSize="small" /> :
|
||||||
|
<TrendingDownIcon fontSize="small" />
|
||||||
|
}
|
||||||
|
{mockMetrics.activeUsers.change}
|
||||||
|
</TrendIndicator>
|
||||||
|
</Box>
|
||||||
|
<AssessmentIcon color="info" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</MetricCard>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 系统状态 */}
|
||||||
|
<Grid container spacing={3} sx={{ mb: 3 }}>
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
系统状态
|
||||||
|
</Typography>
|
||||||
|
<Box mb={2}>
|
||||||
|
<Box display="flex" justifyContent="space-between" mb={1}>
|
||||||
|
<Typography variant="body2">CPU 使用率</Typography>
|
||||||
|
<Typography variant="body2" fontWeight={600}>45%</Typography>
|
||||||
|
</Box>
|
||||||
|
<LinearProgress variant="determinate" value={45} sx={{ height: 8, borderRadius: 4 }} />
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<Box display="flex" justifyContent="space-between" mb={1}>
|
||||||
|
<Typography variant="body2">内存使用率</Typography>
|
||||||
|
<Typography variant="body2" fontWeight={600}>67%</Typography>
|
||||||
|
</Box>
|
||||||
|
<LinearProgress variant="determinate" value={67} color="warning" sx={{ height: 8, borderRadius: 4 }} />
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" mb={1}>
|
||||||
|
<Typography variant="body2">存储使用率</Typography>
|
||||||
|
<Typography variant="body2" fontWeight={600}>23%</Typography>
|
||||||
|
</Box>
|
||||||
|
<LinearProgress variant="determinate" value={23} color="success" sx={{ height: 8, borderRadius: 4 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
知识库状态
|
||||||
|
</Typography>
|
||||||
|
<Box display="flex" flexDirection="column" gap={1}>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">产品文档库</Typography>
|
||||||
|
<StatusChip status="success" label="正常" size="small" />
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">客服FAQ</Typography>
|
||||||
|
<StatusChip status="success" label="正常" size="small" />
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">法律合规</Typography>
|
||||||
|
<StatusChip status="warning" label="同步中" size="small" />
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">培训资料</Typography>
|
||||||
|
<StatusChip status="error" label="错误" size="small" />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 最近查询记录 */}
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
最近查询记录
|
||||||
|
</Typography>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>查询内容</TableCell>
|
||||||
|
<TableCell>用户</TableCell>
|
||||||
|
<TableCell>知识库</TableCell>
|
||||||
|
<TableCell>状态</TableCell>
|
||||||
|
<TableCell>响应时间</TableCell>
|
||||||
|
<TableCell>时间</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{mockRecentQueries.map((query) => (
|
||||||
|
<TableRow key={query.id} hover>
|
||||||
|
<TableCell>
|
||||||
|
<Typography variant="body2" sx={{ maxWidth: '300px', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
||||||
|
{query.query}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{query.user}</TableCell>
|
||||||
|
<TableCell>{query.knowledgeBase}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StatusChip status={query.status} label={
|
||||||
|
query.status === 'success' ? '成功' :
|
||||||
|
query.status === 'warning' ? '警告' : '失败'
|
||||||
|
} size="small" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{query.responseTime}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
{query.timestamp}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dashboard;
|
||||||
218
src/pages/Home.tsx
Normal file
218
src/pages/Home.tsx
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Grid,
|
||||||
|
LinearProgress,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Typography,
|
||||||
|
styled
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
const StyledCard = styled(Card)({
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
|
||||||
|
borderRadius: '8px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const CardTitle = styled(Typography)({
|
||||||
|
fontSize: '1rem',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: '16px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const MetricsContainer = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginBottom: '16px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const Metric = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
});
|
||||||
|
|
||||||
|
const MetricValue = styled(Typography)({
|
||||||
|
fontSize: '1.5rem',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
});
|
||||||
|
|
||||||
|
const MetricLabel = styled(Typography)({
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
color: '#666',
|
||||||
|
});
|
||||||
|
|
||||||
|
const ProgressContainer = styled(Box)({
|
||||||
|
marginBottom: '16px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const ProgressLabel = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
fontSize: '0.65rem',
|
||||||
|
marginBottom: '4px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledLinearProgress = styled(LinearProgress)({
|
||||||
|
height: '8px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const StatusPill = styled(Box)<{ status?: string }>(({ status }) => ({
|
||||||
|
display: 'inline-block',
|
||||||
|
padding: '4px 8px',
|
||||||
|
borderRadius: '12px',
|
||||||
|
fontSize: '0.65rem',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
backgroundColor: status === 'OK' ? '#e6f7ed' : '#ffebee',
|
||||||
|
color: status === 'OK' ? '#00a389' : '#d32f2f',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const InlineNote = styled('span')({
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
color: '#666',
|
||||||
|
fontWeight: 'normal',
|
||||||
|
marginLeft: '4px',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
const recentQueries = [
|
||||||
|
{ query: 'How to reset device firmware?', latency: 732, source: 'manual.pdf', time: '09:21', status: 'OK' },
|
||||||
|
{ query: 'List authentication failure codes', latency: 801, source: 'auth_guide.html', time: '09:18', status: 'OK' },
|
||||||
|
{ query: 'Can we purge stale vectors?', latency: 915, source: 'system_kb', time: '09:10', status: 'OK' },
|
||||||
|
{ query: 'Explain retrieval scoring logic', latency: 845, source: 'design_notes', time: '08:57', status: 'OK' },
|
||||||
|
{ query: 'Pipeline concurrency limits?', latency: 1042, source: 'ops_doc', time: '08:43', status: 'OK' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const Home = () => {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
{/* Knowledge Base Status Card */}
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||||
|
<StyledCard>
|
||||||
|
<CardContent>
|
||||||
|
<CardTitle>Knowledge Base Status</CardTitle>
|
||||||
|
<MetricsContainer>
|
||||||
|
<Metric>
|
||||||
|
<MetricLabel>Documents</MetricLabel>
|
||||||
|
<MetricValue>4,218</MetricValue>
|
||||||
|
</Metric>
|
||||||
|
<Metric>
|
||||||
|
<MetricLabel>Sources</MetricLabel>
|
||||||
|
<MetricValue>17</MetricValue>
|
||||||
|
</Metric>
|
||||||
|
<Metric>
|
||||||
|
<MetricLabel>Vectors</MetricLabel>
|
||||||
|
<MetricValue>1.2M</MetricValue>
|
||||||
|
</Metric>
|
||||||
|
</MetricsContainer>
|
||||||
|
|
||||||
|
<ProgressContainer>
|
||||||
|
<ProgressLabel>
|
||||||
|
<span>Sync Progress</span>
|
||||||
|
<span>62%</span>
|
||||||
|
</ProgressLabel>
|
||||||
|
<StyledLinearProgress variant="determinate" value={62} />
|
||||||
|
</ProgressContainer>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
sx={{
|
||||||
|
backgroundColor: '#1a1a2e',
|
||||||
|
'&:hover': { backgroundColor: '#2a2a3e' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create New Knowledge Base
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</StyledCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Recent Activity Card */}
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||||
|
<StyledCard>
|
||||||
|
<CardContent>
|
||||||
|
<CardTitle>
|
||||||
|
Recent Activity <InlineNote>(latest 24h)</InlineNote>
|
||||||
|
</CardTitle>
|
||||||
|
<Box sx={{ fontSize: '0.7rem', lineHeight: 1.8 }}>
|
||||||
|
<Box>152 user queries processed</Box>
|
||||||
|
<Box>87 new documents ingested</Box>
|
||||||
|
<Box>4 pipeline adjustments</Box>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ marginTop: 'auto', fontSize: '0.65rem', opacity: 0.75, mt: 2 }}>
|
||||||
|
Latency stable at p95 820ms
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</StyledCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Model Overview Card */}
|
||||||
|
<Grid size={{ xs: 12, md: 6, lg: 4 }}>
|
||||||
|
<StyledCard>
|
||||||
|
<CardContent>
|
||||||
|
<CardTitle>Model Overview</CardTitle>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '0.4rem', fontSize: '0.7rem' }}>
|
||||||
|
<Box>Embedding Model: <strong>text-embedding-3-large</strong></Box>
|
||||||
|
<Box>Generator: <strong>gpt-4o-mini</strong></Box>
|
||||||
|
<Box>Reranker: <strong>cross-encoder-v2</strong></Box>
|
||||||
|
<Box>Chunking: 512 tokens</Box>
|
||||||
|
<Box>Retriever Top-K: 8</Box>
|
||||||
|
</Box>
|
||||||
|
<StatusPill status="OK" sx={{ mt: 1 }}>Healthy</StatusPill>
|
||||||
|
</CardContent>
|
||||||
|
</StyledCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* Recent RAG Queries Table */}
|
||||||
|
<Grid size={12}>
|
||||||
|
<StyledCard>
|
||||||
|
<CardContent>
|
||||||
|
<CardTitle>
|
||||||
|
Recent RAG Queries <InlineNote>(latest 5)</InlineNote>
|
||||||
|
</CardTitle>
|
||||||
|
<TableContainer>
|
||||||
|
<Table size="small">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Query</TableCell>
|
||||||
|
<TableCell>Latency (ms)</TableCell>
|
||||||
|
<TableCell>Source</TableCell>
|
||||||
|
<TableCell>Time</TableCell>
|
||||||
|
<TableCell>Status</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{recentQueries.map((row, index) => (
|
||||||
|
<TableRow key={index}>
|
||||||
|
<TableCell>{row.query}</TableCell>
|
||||||
|
<TableCell>{row.latency}</TableCell>
|
||||||
|
<TableCell>{row.source}</TableCell>
|
||||||
|
<TableCell>{row.time}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StatusPill status={row.status}>{row.status}</StatusPill>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</CardContent>
|
||||||
|
</StyledCard>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Home;
|
||||||
265
src/pages/KnowledgeBaseList.tsx
Normal file
265
src/pages/KnowledgeBaseList.tsx
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Grid,
|
||||||
|
Chip,
|
||||||
|
IconButton,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
TextField,
|
||||||
|
InputAdornment,
|
||||||
|
Fab,
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
Search as SearchIcon,
|
||||||
|
Add as AddIcon,
|
||||||
|
MoreVert as MoreVertIcon,
|
||||||
|
Folder as FolderIcon,
|
||||||
|
Description as DocumentIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const PageContainer = styled(Box)(({ theme }) => ({
|
||||||
|
padding: '1.5rem',
|
||||||
|
backgroundColor: '#F8F9FA',
|
||||||
|
minHeight: 'calc(100vh - 60px)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const PageHeader = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const SearchContainer = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
gap: '1rem',
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const KBCard = styled(Card)(({ theme }) => ({
|
||||||
|
height: '100%',
|
||||||
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
border: '1px solid #E5E5E5',
|
||||||
|
'&:hover': {
|
||||||
|
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
||||||
|
transform: 'translateY(-2px)',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusChip = styled(Chip)<{ status: string }>(({ status, theme }) => ({
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
height: '24px',
|
||||||
|
backgroundColor:
|
||||||
|
status === 'active' ? '#E8F5E8' :
|
||||||
|
status === 'processing' ? '#FFF3CD' : '#F8D7DA',
|
||||||
|
color:
|
||||||
|
status === 'active' ? '#155724' :
|
||||||
|
status === 'processing' ? '#856404' : '#721C24',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatsBox = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginTop: '1rem',
|
||||||
|
padding: '0.75rem',
|
||||||
|
backgroundColor: '#F8F9FA',
|
||||||
|
borderRadius: '6px',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatItem = styled(Box)(({ theme }) => ({
|
||||||
|
textAlign: 'center',
|
||||||
|
'& .number': {
|
||||||
|
fontSize: '1.25rem',
|
||||||
|
fontWeight: 600,
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
'& .label': {
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
color: '#666',
|
||||||
|
marginTop: '0.25rem',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockKnowledgeBases = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: '产品文档库',
|
||||||
|
description: '包含所有产品相关的技术文档和用户手册',
|
||||||
|
status: 'active',
|
||||||
|
documents: 156,
|
||||||
|
size: '2.3 GB',
|
||||||
|
lastUpdated: '2024-01-15',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: '客服FAQ',
|
||||||
|
description: '常见问题解答和客服对话记录',
|
||||||
|
status: 'processing',
|
||||||
|
documents: 89,
|
||||||
|
size: '1.1 GB',
|
||||||
|
lastUpdated: '2024-01-14',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: '法律合规',
|
||||||
|
description: '法律条文、合规要求和相关政策文档',
|
||||||
|
status: 'active',
|
||||||
|
documents: 234,
|
||||||
|
size: '3.7 GB',
|
||||||
|
lastUpdated: '2024-01-13',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: '培训资料',
|
||||||
|
description: '员工培训材料和学习资源',
|
||||||
|
status: 'inactive',
|
||||||
|
documents: 67,
|
||||||
|
size: '890 MB',
|
||||||
|
lastUpdated: '2024-01-10',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const KnowledgeBaseList: React.FC = () => {
|
||||||
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||||
|
const [selectedKB, setSelectedKB] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const handleMenuClick = (event: React.MouseEvent<HTMLElement>, kbId: number) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
setSelectedKB(kbId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
setSelectedKB(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredKBs = mockKnowledgeBases.filter(kb =>
|
||||||
|
kb.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
|
kb.description.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<PageHeader>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="#333">
|
||||||
|
知识库管理
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
sx={{ borderRadius: '6px' }}
|
||||||
|
>
|
||||||
|
新建知识库
|
||||||
|
</Button>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<SearchContainer>
|
||||||
|
<TextField
|
||||||
|
placeholder="搜索知识库..."
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SearchIcon color="action" />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
sx={{ width: '400px' }}
|
||||||
|
/>
|
||||||
|
</SearchContainer>
|
||||||
|
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
{filteredKBs.map((kb) => (
|
||||||
|
<Grid key={kb.id} size={{xs:12, sm:6, md:4}}>
|
||||||
|
<KBCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="flex-start">
|
||||||
|
<Box display="flex" alignItems="center" gap={1}>
|
||||||
|
<FolderIcon color="primary" />
|
||||||
|
<Typography variant="h6" fontWeight={600}>
|
||||||
|
{kb.name}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<StatusChip
|
||||||
|
status={kb.status}
|
||||||
|
label={
|
||||||
|
kb.status === 'active' ? '活跃' :
|
||||||
|
kb.status === 'processing' ? '处理中' : '未激活'
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => handleMenuClick(e, kb.id)}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="text.secondary"
|
||||||
|
sx={{ mt: 1, mb: 2 }}
|
||||||
|
>
|
||||||
|
{kb.description}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<StatsBox>
|
||||||
|
<StatItem>
|
||||||
|
<div className="number">{kb.documents}</div>
|
||||||
|
<div className="label">文档数量</div>
|
||||||
|
</StatItem>
|
||||||
|
<StatItem>
|
||||||
|
<div className="number">{kb.size}</div>
|
||||||
|
<div className="label">存储大小</div>
|
||||||
|
</StatItem>
|
||||||
|
</StatsBox>
|
||||||
|
|
||||||
|
<Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: 'block' }}>
|
||||||
|
最后更新: {kb.lastUpdated}
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</KBCard>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
onClose={handleMenuClose}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleMenuClose}>编辑</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose}>查看详情</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose}>导出</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose} sx={{ color: 'error.main' }}>
|
||||||
|
删除
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
|
<Fab
|
||||||
|
color="primary"
|
||||||
|
aria-label="add"
|
||||||
|
sx={{
|
||||||
|
position: 'fixed',
|
||||||
|
bottom: 24,
|
||||||
|
right: 24,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AddIcon />
|
||||||
|
</Fab>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default KnowledgeBaseList;
|
||||||
262
src/pages/Login.tsx
Normal file
262
src/pages/Login.tsx
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Checkbox,
|
||||||
|
Container,
|
||||||
|
FormControlLabel,
|
||||||
|
TextField,
|
||||||
|
Typography,
|
||||||
|
Link,
|
||||||
|
styled
|
||||||
|
} from '@mui/material';
|
||||||
|
|
||||||
|
const LoginContainer = styled(Box)({
|
||||||
|
height: '100vh',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
backgroundColor: '#f5f7fa',
|
||||||
|
});
|
||||||
|
|
||||||
|
const TopBar = styled(Box)({
|
||||||
|
height: '60px',
|
||||||
|
backgroundColor: '#1a1a2e',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '0 20px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const BrandLogo = styled(Box)({
|
||||||
|
width: '40px',
|
||||||
|
height: '40px',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
color: '#1a1a2e',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
borderRadius: '50%',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
fontSize: '1.2rem',
|
||||||
|
});
|
||||||
|
|
||||||
|
const LoginMain = styled(Box)({
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
});
|
||||||
|
|
||||||
|
const LoginCard = styled(Box)({
|
||||||
|
width: '400px',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderRadius: '8px',
|
||||||
|
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
||||||
|
padding: '30px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const ServiceName = styled(Typography)({
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
color: '#666',
|
||||||
|
marginBottom: '10px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const LoginTitle = styled(Typography)({
|
||||||
|
fontSize: '1.5rem',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: '20px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const LoginForm = styled('form')({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '20px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const RememberRow = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
});
|
||||||
|
|
||||||
|
const ActionButtons = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
gap: '10px',
|
||||||
|
marginTop: '10px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const PrimaryButton = styled(Button)({
|
||||||
|
backgroundColor: '#e20074',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#c10062',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const SecondaryButton = styled(Button)({
|
||||||
|
color: '#333',
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: '#e0e0e0',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const HelpSection = styled(Box)({
|
||||||
|
marginTop: '20px',
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
});
|
||||||
|
|
||||||
|
const SocialLogin = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: '10px',
|
||||||
|
marginTop: '15px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const SocialButton = styled(Box)({
|
||||||
|
width: '30px',
|
||||||
|
height: '30px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
backgroundColor: '#e0e0e0',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
cursor: 'pointer',
|
||||||
|
});
|
||||||
|
|
||||||
|
const Footer = styled(Box)({
|
||||||
|
height: '50px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
padding: '0 20px',
|
||||||
|
borderTop: '1px solid #eee',
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
color: '#666',
|
||||||
|
});
|
||||||
|
|
||||||
|
const LegalLinks = styled(Box)({
|
||||||
|
display: 'flex',
|
||||||
|
gap: '15px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const Login = () => {
|
||||||
|
const [username, setUsername] = useState('');
|
||||||
|
const [rememberUser, setRememberUser] = useState(false);
|
||||||
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
const [error, setError] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (!username.trim()) {
|
||||||
|
setError(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsSubmitting(true);
|
||||||
|
setError(false);
|
||||||
|
|
||||||
|
// 模拟登录过程
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate('/');
|
||||||
|
}, 800);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
navigate('/');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LoginContainer>
|
||||||
|
<TopBar>
|
||||||
|
<BrandLogo>T</BrandLogo>
|
||||||
|
</TopBar>
|
||||||
|
|
||||||
|
<LoginMain>
|
||||||
|
<LoginCard>
|
||||||
|
<ServiceName>Servicename</ServiceName>
|
||||||
|
<LoginTitle>
|
||||||
|
Enter Login <br/> Username
|
||||||
|
</LoginTitle>
|
||||||
|
|
||||||
|
<LoginForm onSubmit={handleSubmit} noValidate>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
id="username"
|
||||||
|
name="username"
|
||||||
|
placeholder="Username"
|
||||||
|
autoComplete="username"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
error={error}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<RememberRow>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={rememberUser}
|
||||||
|
onChange={(e) => setRememberUser(e.target.checked)}
|
||||||
|
id="rememberUser"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Remember username"
|
||||||
|
/>
|
||||||
|
<Link href="#" variant="caption">
|
||||||
|
Forgot your username or password?
|
||||||
|
</Link>
|
||||||
|
</RememberRow>
|
||||||
|
|
||||||
|
<ActionButtons>
|
||||||
|
<PrimaryButton
|
||||||
|
type="submit"
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{isSubmitting ? 'Processing...' : 'Next'}
|
||||||
|
</PrimaryButton>
|
||||||
|
<SecondaryButton
|
||||||
|
type="button"
|
||||||
|
variant="contained"
|
||||||
|
fullWidth
|
||||||
|
onClick={handleCancel}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</SecondaryButton>
|
||||||
|
</ActionButtons>
|
||||||
|
</LoginForm>
|
||||||
|
|
||||||
|
<HelpSection>
|
||||||
|
<Link href="#">Do you need help?</Link>
|
||||||
|
<Box mt={1}>
|
||||||
|
No account? <Link href="#">Sign up</Link> or log in with your social network account.
|
||||||
|
</Box>
|
||||||
|
</HelpSection>
|
||||||
|
|
||||||
|
<SocialLogin>
|
||||||
|
<SocialButton aria-label="Login with Facebook">
|
||||||
|
<Link href="#" underline="none" color="inherit">f</Link>
|
||||||
|
</SocialButton>
|
||||||
|
<SocialButton aria-label="Login with Twitter">
|
||||||
|
<Link href="#" underline="none" color="inherit">t</Link>
|
||||||
|
</SocialButton>
|
||||||
|
</SocialLogin>
|
||||||
|
</LoginCard>
|
||||||
|
</LoginMain>
|
||||||
|
|
||||||
|
<Footer>
|
||||||
|
<Box>© Deutsche Telekom AG</Box>
|
||||||
|
<LegalLinks>
|
||||||
|
<Link href="#" color="inherit">Imprint</Link>
|
||||||
|
<Link href="#" color="inherit">Data privacy</Link>
|
||||||
|
</LegalLinks>
|
||||||
|
</Footer>
|
||||||
|
</LoginContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Login;
|
||||||
516
src/pages/MCP.tsx
Normal file
516
src/pages/MCP.tsx
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Grid,
|
||||||
|
Button,
|
||||||
|
Switch,
|
||||||
|
FormControlLabel,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Chip,
|
||||||
|
IconButton,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
TextField,
|
||||||
|
Dialog,
|
||||||
|
DialogTitle,
|
||||||
|
DialogContent,
|
||||||
|
DialogActions,
|
||||||
|
Alert,
|
||||||
|
Tabs,
|
||||||
|
Tab,
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
Add as AddIcon,
|
||||||
|
MoreVert as MoreVertIcon,
|
||||||
|
Settings as SettingsIcon,
|
||||||
|
Link as LinkIcon,
|
||||||
|
Security as SecurityIcon,
|
||||||
|
Speed as SpeedIcon,
|
||||||
|
CheckCircle as CheckCircleIcon,
|
||||||
|
Error as ErrorIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const PageContainer = styled(Box)(({ theme }) => ({
|
||||||
|
padding: '1.5rem',
|
||||||
|
backgroundColor: '#F8F9FA',
|
||||||
|
minHeight: 'calc(100vh - 60px)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const PageHeader = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusCard = styled(Card)(({ theme }) => ({
|
||||||
|
height: '100%',
|
||||||
|
border: '1px solid #E5E5E5',
|
||||||
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
'&:hover': {
|
||||||
|
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusChip = styled(Chip)<{ status: string }>(({ status, theme }) => ({
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
height: '24px',
|
||||||
|
backgroundColor:
|
||||||
|
status === 'connected' ? '#E8F5E8' :
|
||||||
|
status === 'connecting' ? '#FFF3CD' :
|
||||||
|
status === 'error' ? '#F8D7DA' : '#F8F9FA',
|
||||||
|
color:
|
||||||
|
status === 'connected' ? '#155724' :
|
||||||
|
status === 'connecting' ? '#856404' :
|
||||||
|
status === 'error' ? '#721C24' : '#666',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockMCPServers = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'File System Server',
|
||||||
|
description: '文件系统操作服务器',
|
||||||
|
url: 'mcp://localhost:3001',
|
||||||
|
status: 'connected',
|
||||||
|
version: '1.0.0',
|
||||||
|
tools: ['read_file', 'write_file', 'list_directory'],
|
||||||
|
lastPing: '2024-01-15 14:30:25',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Database Server',
|
||||||
|
description: '数据库查询服务器',
|
||||||
|
url: 'mcp://db.example.com:3002',
|
||||||
|
status: 'connected',
|
||||||
|
version: '1.2.1',
|
||||||
|
tools: ['query_sql', 'execute_sql', 'get_schema'],
|
||||||
|
lastPing: '2024-01-15 14:30:20',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Web Scraper',
|
||||||
|
description: '网页抓取服务器',
|
||||||
|
url: 'mcp://scraper.example.com:3003',
|
||||||
|
status: 'connecting',
|
||||||
|
version: '0.9.5',
|
||||||
|
tools: ['scrape_url', 'extract_text', 'get_links'],
|
||||||
|
lastPing: '2024-01-15 14:28:15',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'API Gateway',
|
||||||
|
description: 'API网关服务器',
|
||||||
|
url: 'mcp://api.example.com:3004',
|
||||||
|
status: 'error',
|
||||||
|
version: '2.1.0',
|
||||||
|
tools: ['call_api', 'auth_token', 'rate_limit'],
|
||||||
|
lastPing: '2024-01-15 14:25:10',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const MCP: React.FC = () => {
|
||||||
|
const [tabValue, setTabValue] = useState(0);
|
||||||
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||||
|
const [selectedServer, setSelectedServer] = useState<number | null>(null);
|
||||||
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
const [newServer, setNewServer] = useState({
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
description: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
|
||||||
|
setTabValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClick = (event: React.MouseEvent<HTMLElement>, serverId: number) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
setSelectedServer(serverId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
setSelectedServer(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAddServer = () => {
|
||||||
|
setDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDialogClose = () => {
|
||||||
|
setDialogOpen(false);
|
||||||
|
setNewServer({ name: '', url: '', description: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveServer = () => {
|
||||||
|
// 保存服务器逻辑
|
||||||
|
console.log('添加服务器:', newServer);
|
||||||
|
handleDialogClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const connectedServers = mockMCPServers.filter(s => s.status === 'connected').length;
|
||||||
|
const totalTools = mockMCPServers.reduce((acc, server) => acc + server.tools.length, 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<PageHeader>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="#333">
|
||||||
|
MCP 协议管理
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.5 }}>
|
||||||
|
Model Context Protocol - 模型上下文协议服务器管理
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
onClick={handleAddServer}
|
||||||
|
sx={{ borderRadius: '6px' }}
|
||||||
|
>
|
||||||
|
添加服务器
|
||||||
|
</Button>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
|
||||||
|
<Tabs value={tabValue} onChange={handleTabChange}>
|
||||||
|
<Tab label="服务器管理" />
|
||||||
|
<Tab label="工具配置" />
|
||||||
|
<Tab label="协议监控" />
|
||||||
|
</Tabs>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{tabValue === 0 && (
|
||||||
|
<>
|
||||||
|
{/* 状态概览 */}
|
||||||
|
<Grid container spacing={3} sx={{ mb: 3 }}>
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<StatusCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
连接服务器
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="success.main">
|
||||||
|
{connectedServers}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<CheckCircleIcon color="success" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</StatusCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<StatusCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
总服务器数
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="primary">
|
||||||
|
{mockMCPServers.length}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<LinkIcon color="primary" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</StatusCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<StatusCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
可用工具
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="info.main">
|
||||||
|
{totalTools}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<SettingsIcon color="info" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</StatusCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<StatusCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
平均延迟
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="warning.main">
|
||||||
|
45ms
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<SpeedIcon color="warning" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</StatusCard>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 服务器列表 */}
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
MCP 服务器列表
|
||||||
|
</Typography>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>服务器名称</TableCell>
|
||||||
|
<TableCell>URL</TableCell>
|
||||||
|
<TableCell>状态</TableCell>
|
||||||
|
<TableCell>版本</TableCell>
|
||||||
|
<TableCell>工具数量</TableCell>
|
||||||
|
<TableCell>最后心跳</TableCell>
|
||||||
|
<TableCell>操作</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{mockMCPServers.map((server) => (
|
||||||
|
<TableRow key={server.id} hover>
|
||||||
|
<TableCell>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="body2" fontWeight={600}>
|
||||||
|
{server.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
{server.description}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography variant="body2" fontFamily="monospace">
|
||||||
|
{server.url}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StatusChip
|
||||||
|
status={server.status}
|
||||||
|
label={
|
||||||
|
server.status === 'connected' ? '已连接' :
|
||||||
|
server.status === 'connecting' ? '连接中' : '错误'
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Chip
|
||||||
|
label={server.version}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography variant="body2">
|
||||||
|
{server.tools.length} 个工具
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
{server.lastPing}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => handleMenuClick(e, server.id)}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tabValue === 1 && (
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
工具配置
|
||||||
|
</Typography>
|
||||||
|
<Alert severity="info" sx={{ mb: 2 }}>
|
||||||
|
配置各个 MCP 服务器提供的工具和权限设置
|
||||||
|
</Alert>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{mockMCPServers.map((server) => (
|
||||||
|
<Grid item xs={12} md={6} key={server.id}>
|
||||||
|
<Card variant="outlined">
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="subtitle1" fontWeight={600} mb={1}>
|
||||||
|
{server.name}
|
||||||
|
</Typography>
|
||||||
|
<Box display="flex" flexDirection="column" gap={1}>
|
||||||
|
{server.tools.map((tool, index) => (
|
||||||
|
<FormControlLabel
|
||||||
|
key={index}
|
||||||
|
control={<Switch defaultChecked size="small" />}
|
||||||
|
label={
|
||||||
|
<Typography variant="body2" fontFamily="monospace">
|
||||||
|
{tool}
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tabValue === 2 && (
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
<SecurityIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
|
||||||
|
安全监控
|
||||||
|
</Typography>
|
||||||
|
<Box display="flex" flexDirection="column" gap={2}>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">SSL/TLS 加密</Typography>
|
||||||
|
<CheckCircleIcon color="success" />
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">身份验证</Typography>
|
||||||
|
<CheckCircleIcon color="success" />
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">访问控制</Typography>
|
||||||
|
<CheckCircleIcon color="success" />
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||||
|
<Typography variant="body2">审计日志</Typography>
|
||||||
|
<ErrorIcon color="error" />
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
<SpeedIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
|
||||||
|
性能监控
|
||||||
|
</Typography>
|
||||||
|
<Box display="flex" flexDirection="column" gap={2}>
|
||||||
|
<Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" mb={1}>
|
||||||
|
<Typography variant="body2">平均响应时间</Typography>
|
||||||
|
<Typography variant="body2" fontWeight={600}>45ms</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box bgcolor="#F8F9FA" p={1} borderRadius="4px">
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
过去24小时内的平均值
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Box display="flex" justifyContent="space-between" mb={1}>
|
||||||
|
<Typography variant="body2">成功率</Typography>
|
||||||
|
<Typography variant="body2" fontWeight={600} color="success.main">
|
||||||
|
99.2%
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box bgcolor="#F8F9FA" p={1} borderRadius="4px">
|
||||||
|
<Typography variant="caption" color="text.secondary">
|
||||||
|
过去24小时内的成功率
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 菜单 */}
|
||||||
|
<Menu
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
onClose={handleMenuClose}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleMenuClose}>
|
||||||
|
<SettingsIcon sx={{ mr: 1 }} fontSize="small" />
|
||||||
|
配置
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose}>测试连接</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose}>查看日志</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose} sx={{ color: 'error.main' }}>
|
||||||
|
断开连接
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
|
{/* 添加服务器对话框 */}
|
||||||
|
<Dialog open={dialogOpen} onClose={handleDialogClose} maxWidth="sm" fullWidth>
|
||||||
|
<DialogTitle>添加 MCP 服务器</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Box display="flex" flexDirection="column" gap={2} pt={1}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="服务器名称"
|
||||||
|
value={newServer.name}
|
||||||
|
onChange={(e) => setNewServer(prev => ({ ...prev, name: e.target.value }))}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="服务器 URL"
|
||||||
|
placeholder="mcp://localhost:3000"
|
||||||
|
value={newServer.url}
|
||||||
|
onChange={(e) => setNewServer(prev => ({ ...prev, url: e.target.value }))}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="描述"
|
||||||
|
multiline
|
||||||
|
rows={3}
|
||||||
|
value={newServer.description}
|
||||||
|
onChange={(e) => setNewServer(prev => ({ ...prev, description: e.target.value }))}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleDialogClose}>取消</Button>
|
||||||
|
<Button onClick={handleSaveServer} variant="contained">
|
||||||
|
添加
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MCP;
|
||||||
540
src/pages/ModelsResources.tsx
Normal file
540
src/pages/ModelsResources.tsx
Normal file
@@ -0,0 +1,540 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Grid,
|
||||||
|
Button,
|
||||||
|
Chip,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Paper,
|
||||||
|
LinearProgress,
|
||||||
|
IconButton,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
Tabs,
|
||||||
|
Tab,
|
||||||
|
TextField,
|
||||||
|
InputAdornment,
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
Memory as MemoryIcon,
|
||||||
|
Storage as StorageIcon,
|
||||||
|
Speed as SpeedIcon,
|
||||||
|
CloudDownload as CloudDownloadIcon,
|
||||||
|
Settings as SettingsIcon,
|
||||||
|
MoreVert as MoreVertIcon,
|
||||||
|
Search as SearchIcon,
|
||||||
|
Add as AddIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const PageContainer = styled(Box)(({ theme }) => ({
|
||||||
|
padding: '1.5rem',
|
||||||
|
backgroundColor: '#F8F9FA',
|
||||||
|
minHeight: 'calc(100vh - 60px)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const PageHeader = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ResourceCard = styled(Card)(({ theme }) => ({
|
||||||
|
height: '100%',
|
||||||
|
border: '1px solid #E5E5E5',
|
||||||
|
transition: 'all 0.2s ease-in-out',
|
||||||
|
'&:hover': {
|
||||||
|
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusChip = styled(Chip)<{ status: string }>(({ status, theme }) => ({
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
height: '24px',
|
||||||
|
backgroundColor:
|
||||||
|
status === 'active' ? '#E8F5E8' :
|
||||||
|
status === 'loading' ? '#FFF3CD' :
|
||||||
|
status === 'error' ? '#F8D7DA' : '#F8F9FA',
|
||||||
|
color:
|
||||||
|
status === 'active' ? '#155724' :
|
||||||
|
status === 'loading' ? '#856404' :
|
||||||
|
status === 'error' ? '#721C24' : '#666',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const UsageBar = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.5rem',
|
||||||
|
marginTop: '0.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockModels = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'GPT-4',
|
||||||
|
type: 'LLM',
|
||||||
|
provider: 'OpenAI',
|
||||||
|
status: 'active',
|
||||||
|
usage: 75,
|
||||||
|
cost: '$234.56',
|
||||||
|
requests: '12.3K',
|
||||||
|
latency: '1.2s',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'text-embedding-ada-002',
|
||||||
|
type: 'Embedding',
|
||||||
|
provider: 'OpenAI',
|
||||||
|
status: 'active',
|
||||||
|
usage: 45,
|
||||||
|
cost: '$89.12',
|
||||||
|
requests: '45.6K',
|
||||||
|
latency: '0.3s',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Claude-3-Sonnet',
|
||||||
|
type: 'LLM',
|
||||||
|
provider: 'Anthropic',
|
||||||
|
status: 'loading',
|
||||||
|
usage: 0,
|
||||||
|
cost: '$0.00',
|
||||||
|
requests: '0',
|
||||||
|
latency: 'N/A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: 'BGE-Large-ZH',
|
||||||
|
type: 'Embedding',
|
||||||
|
provider: 'BAAI',
|
||||||
|
status: 'error',
|
||||||
|
usage: 0,
|
||||||
|
cost: '$0.00',
|
||||||
|
requests: '0',
|
||||||
|
latency: 'N/A',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockResources = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'GPU-Server-01',
|
||||||
|
type: 'GPU',
|
||||||
|
specs: 'NVIDIA A100 80GB',
|
||||||
|
usage: 85,
|
||||||
|
status: 'active',
|
||||||
|
location: '北京机房',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'CPU-Cluster-01',
|
||||||
|
type: 'CPU',
|
||||||
|
specs: '64 Core Intel Xeon',
|
||||||
|
usage: 45,
|
||||||
|
status: 'active',
|
||||||
|
location: '上海机房',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Storage-Pool-01',
|
||||||
|
type: 'Storage',
|
||||||
|
specs: '10TB NVMe SSD',
|
||||||
|
usage: 67,
|
||||||
|
status: 'active',
|
||||||
|
location: '深圳机房',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ModelsResources: React.FC = () => {
|
||||||
|
const [tabValue, setTabValue] = useState(0);
|
||||||
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||||
|
const [selectedItem, setSelectedItem] = useState<number | null>(null);
|
||||||
|
|
||||||
|
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
|
||||||
|
setTabValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClick = (event: React.MouseEvent<HTMLElement>, itemId: number) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
setSelectedItem(itemId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMenuClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
setSelectedItem(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredModels = mockModels.filter(model =>
|
||||||
|
model.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
|
model.provider.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredResources = mockResources.filter(resource =>
|
||||||
|
resource.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
|
resource.type.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<PageHeader>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="#333">
|
||||||
|
模型与资源
|
||||||
|
</Typography>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
sx={{ borderRadius: '6px' }}
|
||||||
|
>
|
||||||
|
添加模型
|
||||||
|
</Button>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
|
||||||
|
<Tabs value={tabValue} onChange={handleTabChange}>
|
||||||
|
<Tab label="AI 模型" />
|
||||||
|
<Tab label="计算资源" />
|
||||||
|
</Tabs>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box display="flex" gap={2} mb={3}>
|
||||||
|
<TextField
|
||||||
|
placeholder={tabValue === 0 ? "搜索模型..." : "搜索资源..."}
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SearchIcon color="action" />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
sx={{ width: '400px' }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{tabValue === 0 && (
|
||||||
|
<>
|
||||||
|
{/* 模型概览卡片 */}
|
||||||
|
<Grid container spacing={3} sx={{ mb: 3 }}>
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<ResourceCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
活跃模型
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="primary">
|
||||||
|
{mockModels.filter(m => m.status === 'active').length}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<MemoryIcon color="primary" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResourceCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<ResourceCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
总请求数
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="success.main">
|
||||||
|
57.9K
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<SpeedIcon color="success" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResourceCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<ResourceCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
总成本
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="warning.main">
|
||||||
|
$323.68
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<CloudDownloadIcon color="warning" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResourceCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<ResourceCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
平均延迟
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="info.main">
|
||||||
|
0.8s
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<SpeedIcon color="info" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResourceCard>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 模型列表 */}
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
模型列表
|
||||||
|
</Typography>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>模型名称</TableCell>
|
||||||
|
<TableCell>类型</TableCell>
|
||||||
|
<TableCell>提供商</TableCell>
|
||||||
|
<TableCell>状态</TableCell>
|
||||||
|
<TableCell>使用率</TableCell>
|
||||||
|
<TableCell>请求数</TableCell>
|
||||||
|
<TableCell>成本</TableCell>
|
||||||
|
<TableCell>延迟</TableCell>
|
||||||
|
<TableCell>操作</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{filteredModels.map((model) => (
|
||||||
|
<TableRow key={model.id} hover>
|
||||||
|
<TableCell>
|
||||||
|
<Typography variant="body2" fontWeight={600}>
|
||||||
|
{model.name}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Chip
|
||||||
|
label={model.type}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
color={model.type === 'LLM' ? 'primary' : 'secondary'}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{model.provider}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StatusChip
|
||||||
|
status={model.status}
|
||||||
|
label={
|
||||||
|
model.status === 'active' ? '活跃' :
|
||||||
|
model.status === 'loading' ? '加载中' : '错误'
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<UsageBar>
|
||||||
|
<LinearProgress
|
||||||
|
variant="determinate"
|
||||||
|
value={model.usage}
|
||||||
|
sx={{ width: '60px', height: '6px', borderRadius: '3px' }}
|
||||||
|
color={model.usage > 80 ? 'error' : model.usage > 60 ? 'warning' : 'primary'}
|
||||||
|
/>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
{model.usage}%
|
||||||
|
</Typography>
|
||||||
|
</UsageBar>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{model.requests}</TableCell>
|
||||||
|
<TableCell>{model.cost}</TableCell>
|
||||||
|
<TableCell>{model.latency}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => handleMenuClick(e, model.id)}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{tabValue === 1 && (
|
||||||
|
<>
|
||||||
|
{/* 资源概览卡片 */}
|
||||||
|
<Grid container spacing={3} sx={{ mb: 3 }}>
|
||||||
|
<Grid item xs={12} sm={6} md={4}>
|
||||||
|
<ResourceCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
GPU 使用率
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="error.main">
|
||||||
|
85%
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<MemoryIcon color="error" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResourceCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={4}>
|
||||||
|
<ResourceCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
CPU 使用率
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="warning.main">
|
||||||
|
45%
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<SpeedIcon color="warning" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResourceCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} sm={6} md={4}>
|
||||||
|
<ResourceCard>
|
||||||
|
<CardContent>
|
||||||
|
<Box display="flex" alignItems="center" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
<Typography color="text.secondary" variant="body2">
|
||||||
|
存储使用率
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="success.main">
|
||||||
|
67%
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<StorageIcon color="success" sx={{ fontSize: '3rem', opacity: 0.3 }} />
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</ResourceCard>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{/* 资源列表 */}
|
||||||
|
<Card sx={{ border: '1px solid #E5E5E5' }}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
计算资源
|
||||||
|
</Typography>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>资源名称</TableCell>
|
||||||
|
<TableCell>类型</TableCell>
|
||||||
|
<TableCell>规格</TableCell>
|
||||||
|
<TableCell>使用率</TableCell>
|
||||||
|
<TableCell>状态</TableCell>
|
||||||
|
<TableCell>位置</TableCell>
|
||||||
|
<TableCell>操作</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{filteredResources.map((resource) => (
|
||||||
|
<TableRow key={resource.id} hover>
|
||||||
|
<TableCell>
|
||||||
|
<Typography variant="body2" fontWeight={600}>
|
||||||
|
{resource.name}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Chip
|
||||||
|
label={resource.type}
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
color={
|
||||||
|
resource.type === 'GPU' ? 'error' :
|
||||||
|
resource.type === 'CPU' ? 'warning' : 'success'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{resource.specs}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<UsageBar>
|
||||||
|
<LinearProgress
|
||||||
|
variant="determinate"
|
||||||
|
value={resource.usage}
|
||||||
|
sx={{ width: '80px', height: '6px', borderRadius: '3px' }}
|
||||||
|
color={resource.usage > 80 ? 'error' : resource.usage > 60 ? 'warning' : 'primary'}
|
||||||
|
/>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
{resource.usage}%
|
||||||
|
</Typography>
|
||||||
|
</UsageBar>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<StatusChip
|
||||||
|
status={resource.status}
|
||||||
|
label={resource.status === 'active' ? '活跃' : '离线'}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{resource.location}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => handleMenuClick(e, resource.id)}
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Menu
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={Boolean(anchorEl)}
|
||||||
|
onClose={handleMenuClose}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={handleMenuClose}>
|
||||||
|
<SettingsIcon sx={{ mr: 1 }} fontSize="small" />
|
||||||
|
配置
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose}>查看详情</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose}>监控</MenuItem>
|
||||||
|
<MenuItem onClick={handleMenuClose} sx={{ color: 'error.main' }}>
|
||||||
|
停用
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModelsResources;
|
||||||
349
src/pages/PipelineConfig.tsx
Normal file
349
src/pages/PipelineConfig.tsx
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Grid,
|
||||||
|
Button,
|
||||||
|
Switch,
|
||||||
|
FormControlLabel,
|
||||||
|
Slider,
|
||||||
|
TextField,
|
||||||
|
Select,
|
||||||
|
MenuItem,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
Chip,
|
||||||
|
Divider,
|
||||||
|
Alert,
|
||||||
|
LinearProgress,
|
||||||
|
} from '@mui/material';
|
||||||
|
import {
|
||||||
|
Settings as SettingsIcon,
|
||||||
|
PlayArrow as PlayIcon,
|
||||||
|
Stop as StopIcon,
|
||||||
|
Refresh as RefreshIcon,
|
||||||
|
Save as SaveIcon,
|
||||||
|
} from '@mui/icons-material';
|
||||||
|
import { styled } from '@mui/material/styles';
|
||||||
|
|
||||||
|
const PageContainer = styled(Box)(({ theme }) => ({
|
||||||
|
padding: '1.5rem',
|
||||||
|
backgroundColor: '#F8F9FA',
|
||||||
|
minHeight: 'calc(100vh - 60px)',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const PageHeader = styled(Box)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ConfigCard = styled(Card)(({ theme }) => ({
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
border: '1px solid #E5E5E5',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ConfigSection = styled(Box)(({ theme }) => ({
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
'&:last-child': {
|
||||||
|
marginBottom: 0,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StatusIndicator = styled(Box)<{ status: 'running' | 'stopped' | 'error' }>(({ status, theme }) => ({
|
||||||
|
display: 'inline-flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.5rem',
|
||||||
|
padding: '0.25rem 0.75rem',
|
||||||
|
borderRadius: '12px',
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
fontWeight: 500,
|
||||||
|
backgroundColor:
|
||||||
|
status === 'running' ? '#E8F5E8' :
|
||||||
|
status === 'stopped' ? '#F8F9FA' : '#F8D7DA',
|
||||||
|
color:
|
||||||
|
status === 'running' ? '#155724' :
|
||||||
|
status === 'stopped' ? '#666' : '#721C24',
|
||||||
|
'&::before': {
|
||||||
|
content: '""',
|
||||||
|
width: '8px',
|
||||||
|
height: '8px',
|
||||||
|
borderRadius: '50%',
|
||||||
|
backgroundColor:
|
||||||
|
status === 'running' ? '#28A745' :
|
||||||
|
status === 'stopped' ? '#6C757D' : '#DC3545',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const PipelineConfig: React.FC = () => {
|
||||||
|
const [pipelineStatus, setPipelineStatus] = useState<'running' | 'stopped' | 'error'>('stopped');
|
||||||
|
const [config, setConfig] = useState({
|
||||||
|
enabled: false,
|
||||||
|
chunkSize: 512,
|
||||||
|
chunkOverlap: 50,
|
||||||
|
embeddingModel: 'text-embedding-ada-002',
|
||||||
|
retrievalTopK: 5,
|
||||||
|
temperature: 0.7,
|
||||||
|
maxTokens: 2048,
|
||||||
|
systemPrompt: '你是一个专业的AI助手,请基于提供的知识库内容回答用户问题。',
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleConfigChange = (key: string, value: any) => {
|
||||||
|
setConfig(prev => ({ ...prev, [key]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleStartPipeline = () => {
|
||||||
|
setPipelineStatus('running');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleStopPipeline = () => {
|
||||||
|
setPipelineStatus('stopped');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSaveConfig = () => {
|
||||||
|
// 保存配置逻辑
|
||||||
|
console.log('保存配置:', config);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<PageHeader>
|
||||||
|
<Box>
|
||||||
|
<Typography variant="h4" fontWeight={600} color="#333">
|
||||||
|
RAG Pipeline 配置
|
||||||
|
</Typography>
|
||||||
|
<Box display="flex" alignItems="center" gap={2} mt={1}>
|
||||||
|
<StatusIndicator status={pipelineStatus}>
|
||||||
|
{pipelineStatus === 'running' ? '运行中' :
|
||||||
|
pipelineStatus === 'stopped' ? '已停止' : '错误'}
|
||||||
|
</StatusIndicator>
|
||||||
|
{pipelineStatus === 'running' && (
|
||||||
|
<LinearProgress sx={{ width: '200px', height: '6px', borderRadius: '3px' }} />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box display="flex" gap={1}>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<SaveIcon />}
|
||||||
|
onClick={handleSaveConfig}
|
||||||
|
>
|
||||||
|
保存配置
|
||||||
|
</Button>
|
||||||
|
{pipelineStatus === 'running' ? (
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="error"
|
||||||
|
startIcon={<StopIcon />}
|
||||||
|
onClick={handleStopPipeline}
|
||||||
|
>
|
||||||
|
停止
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<PlayIcon />}
|
||||||
|
onClick={handleStartPipeline}
|
||||||
|
>
|
||||||
|
启动
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</PageHeader>
|
||||||
|
|
||||||
|
<Grid container spacing={3}>
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<ConfigCard>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
<SettingsIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
|
||||||
|
基础配置
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={config.enabled}
|
||||||
|
onChange={(e) => handleConfigChange('enabled', e.target.checked)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="启用 RAG Pipeline"
|
||||||
|
/>
|
||||||
|
</ConfigSection>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<Typography gutterBottom>文档分块大小</Typography>
|
||||||
|
<Slider
|
||||||
|
value={config.chunkSize}
|
||||||
|
onChange={(_, value) => handleConfigChange('chunkSize', value)}
|
||||||
|
min={128}
|
||||||
|
max={2048}
|
||||||
|
step={64}
|
||||||
|
marks={[
|
||||||
|
{ value: 128, label: '128' },
|
||||||
|
{ value: 512, label: '512' },
|
||||||
|
{ value: 1024, label: '1024' },
|
||||||
|
{ value: 2048, label: '2048' },
|
||||||
|
]}
|
||||||
|
valueLabelDisplay="on"
|
||||||
|
/>
|
||||||
|
</ConfigSection>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<Typography gutterBottom>分块重叠 (%)</Typography>
|
||||||
|
<Slider
|
||||||
|
value={config.chunkOverlap}
|
||||||
|
onChange={(_, value) => handleConfigChange('chunkOverlap', value)}
|
||||||
|
min={0}
|
||||||
|
max={50}
|
||||||
|
step={5}
|
||||||
|
valueLabelDisplay="on"
|
||||||
|
/>
|
||||||
|
</ConfigSection>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<FormControl fullWidth>
|
||||||
|
<InputLabel>嵌入模型</InputLabel>
|
||||||
|
<Select
|
||||||
|
value={config.embeddingModel}
|
||||||
|
onChange={(e) => handleConfigChange('embeddingModel', e.target.value)}
|
||||||
|
label="嵌入模型"
|
||||||
|
>
|
||||||
|
<MenuItem value="text-embedding-ada-002">text-embedding-ada-002</MenuItem>
|
||||||
|
<MenuItem value="text-embedding-3-small">text-embedding-3-small</MenuItem>
|
||||||
|
<MenuItem value="text-embedding-3-large">text-embedding-3-large</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
</ConfigSection>
|
||||||
|
</CardContent>
|
||||||
|
</ConfigCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={6}>
|
||||||
|
<ConfigCard>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
检索与生成配置
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="检索文档数量 (Top-K)"
|
||||||
|
type="number"
|
||||||
|
value={config.retrievalTopK}
|
||||||
|
onChange={(e) => handleConfigChange('retrievalTopK', parseInt(e.target.value))}
|
||||||
|
inputProps={{ min: 1, max: 20 }}
|
||||||
|
/>
|
||||||
|
</ConfigSection>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<Typography gutterBottom>生成温度</Typography>
|
||||||
|
<Slider
|
||||||
|
value={config.temperature}
|
||||||
|
onChange={(_, value) => handleConfigChange('temperature', value)}
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
step={0.1}
|
||||||
|
marks={[
|
||||||
|
{ value: 0, label: '0' },
|
||||||
|
{ value: 0.5, label: '0.5' },
|
||||||
|
{ value: 1, label: '1' },
|
||||||
|
]}
|
||||||
|
valueLabelDisplay="on"
|
||||||
|
/>
|
||||||
|
</ConfigSection>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="最大输出Token数"
|
||||||
|
type="number"
|
||||||
|
value={config.maxTokens}
|
||||||
|
onChange={(e) => handleConfigChange('maxTokens', parseInt(e.target.value))}
|
||||||
|
inputProps={{ min: 256, max: 4096 }}
|
||||||
|
/>
|
||||||
|
</ConfigSection>
|
||||||
|
|
||||||
|
<ConfigSection>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="系统提示词"
|
||||||
|
multiline
|
||||||
|
rows={4}
|
||||||
|
value={config.systemPrompt}
|
||||||
|
onChange={(e) => handleConfigChange('systemPrompt', e.target.value)}
|
||||||
|
/>
|
||||||
|
</ConfigSection>
|
||||||
|
</CardContent>
|
||||||
|
</ConfigCard>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<ConfigCard>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6" fontWeight={600} mb={2}>
|
||||||
|
Pipeline 状态监控
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<Box textAlign="center" p={2} bgcolor="#F8F9FA" borderRadius="6px">
|
||||||
|
<Typography variant="h4" color="primary" fontWeight={600}>
|
||||||
|
1,234
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
已处理文档
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<Box textAlign="center" p={2} bgcolor="#F8F9FA" borderRadius="6px">
|
||||||
|
<Typography variant="h4" color="success.main" fontWeight={600}>
|
||||||
|
98.5%
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
成功率
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<Box textAlign="center" p={2} bgcolor="#F8F9FA" borderRadius="6px">
|
||||||
|
<Typography variant="h4" color="warning.main" fontWeight={600}>
|
||||||
|
2.3s
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
平均响应时间
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3}>
|
||||||
|
<Box textAlign="center" p={2} bgcolor="#F8F9FA" borderRadius="6px">
|
||||||
|
<Typography variant="h4" color="info.main" fontWeight={600}>
|
||||||
|
156
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" color="text.secondary">
|
||||||
|
今日查询数
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
{pipelineStatus === 'error' && (
|
||||||
|
<Alert severity="error" sx={{ mt: 2 }}>
|
||||||
|
Pipeline 运行出现错误,请检查配置和日志。
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</ConfigCard>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PipelineConfig;
|
||||||
32
src/routes/index.tsx
Normal file
32
src/routes/index.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||||
|
import MainLayout from '../components/Layout/MainLayout';
|
||||||
|
import Login from '../pages/Login';
|
||||||
|
import Home from '../pages/Home';
|
||||||
|
import KnowledgeBaseList from '../pages/KnowledgeBaseList';
|
||||||
|
import PipelineConfig from '../pages/PipelineConfig';
|
||||||
|
import Dashboard from '../pages/Dashboard';
|
||||||
|
import ModelsResources from '../pages/ModelsResources';
|
||||||
|
import MCP from '../pages/MCP';
|
||||||
|
|
||||||
|
const AppRoutes = () => {
|
||||||
|
return (
|
||||||
|
<Routes>
|
||||||
|
<Route path="/login" element={<Login />} />
|
||||||
|
|
||||||
|
{/* 使用MainLayout作为受保护路由的布局 */}
|
||||||
|
<Route path="/" element={<MainLayout />}>
|
||||||
|
<Route index element={<Home />} />
|
||||||
|
<Route path="kb-list" element={<KnowledgeBaseList />} />
|
||||||
|
<Route path="pipeline-config" element={<PipelineConfig />} />
|
||||||
|
<Route path="dashboard" element={<Dashboard />} />
|
||||||
|
<Route path="models-resources" element={<ModelsResources />} />
|
||||||
|
<Route path="mcp" element={<MCP />} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
{/* 处理未匹配的路由 */}
|
||||||
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
|
</Routes>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppRoutes;
|
||||||
164
src/theme/index.ts
Normal file
164
src/theme/index.ts
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import { createTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
|
// Company branding colors extracted from web_prototype CSS
|
||||||
|
const brandColors = {
|
||||||
|
primary: '#E20074',
|
||||||
|
primaryHover: '#C40062',
|
||||||
|
background: '#F0F0F0',
|
||||||
|
surface: '#FFFFFF',
|
||||||
|
text: '#222',
|
||||||
|
textSecondary: '#555',
|
||||||
|
border: '#E2E2E2',
|
||||||
|
borderStrong: '#CFCFCF',
|
||||||
|
success: '#1E9E59',
|
||||||
|
danger: '#D22C32',
|
||||||
|
warning: '#D89200',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const theme = createTheme({
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
main: brandColors.primary,
|
||||||
|
dark: brandColors.primaryHover,
|
||||||
|
contrastText: '#FFFFFF',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: brandColors.primary,
|
||||||
|
dark: brandColors.primaryHover,
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
default: brandColors.background,
|
||||||
|
paper: brandColors.surface,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
primary: brandColors.text,
|
||||||
|
secondary: brandColors.textSecondary,
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
main: brandColors.success,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
main: brandColors.danger,
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
main: brandColors.warning,
|
||||||
|
},
|
||||||
|
divider: brandColors.border,
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: '"Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif',
|
||||||
|
h1: {
|
||||||
|
fontWeight: 700,
|
||||||
|
letterSpacing: '0.5px',
|
||||||
|
},
|
||||||
|
h2: {
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.5px',
|
||||||
|
},
|
||||||
|
h3: {
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.3px',
|
||||||
|
},
|
||||||
|
body1: {
|
||||||
|
fontSize: '0.875rem',
|
||||||
|
},
|
||||||
|
body2: {
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.3px',
|
||||||
|
textTransform: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
borderRadius: 10,
|
||||||
|
},
|
||||||
|
shadows: [
|
||||||
|
'none',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 4px 12px -2px rgba(226,0,116,0.45)',
|
||||||
|
'0 6px 14px -2px rgba(226,0,116,0.5)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
'0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
],
|
||||||
|
components: {
|
||||||
|
MuiButton: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderRadius: '8px',
|
||||||
|
padding: '0.65rem 1.1rem',
|
||||||
|
fontSize: '0.8rem',
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.3px',
|
||||||
|
},
|
||||||
|
contained: {
|
||||||
|
boxShadow: '0 4px 10px -2px rgba(226,0,116,0.45)',
|
||||||
|
'&:hover': {
|
||||||
|
transform: 'translateY(-2px)',
|
||||||
|
boxShadow: '0 6px 14px -2px rgba(226,0,116,0.5)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiCard: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
borderRadius: '10px',
|
||||||
|
border: `1px solid ${brandColors.border}`,
|
||||||
|
boxShadow: '0 2px 4px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiTextField: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
borderRadius: '8px',
|
||||||
|
'&:hover .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: brandColors.primary,
|
||||||
|
},
|
||||||
|
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
||||||
|
borderColor: brandColors.primary,
|
||||||
|
boxShadow: `0 0 0 3px rgba(226,0,116,0.25)`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiLinearProgress: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
height: '8px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
backgroundColor: '#ECECEC',
|
||||||
|
},
|
||||||
|
bar: {
|
||||||
|
borderRadius: '4px',
|
||||||
|
background: `linear-gradient(90deg, ${brandColors.primary}, #FF4DA8)`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default theme;
|
||||||
Reference in New Issue
Block a user