Added some widgets

Removed menu button
added terminal functional button
Added Dashboard button on User button
Added warning theming color
This commit is contained in:
SnippetsX 2024-11-04 00:59:56 +03:00
parent 1eece4f160
commit c711fb949f
9 changed files with 578 additions and 149 deletions

298
package-lock.json generated
View File

@ -15,13 +15,15 @@
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"@xterm/xterm": "^5.5.0",
"codegen": "^0.1.0", "codegen": "^0.1.0",
"eslint-plugin-react": "^7.37.1", "eslint-plugin-react": "^7.37.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-router-dom": "^6.27.0", "react-router-dom": "^6.27.0",
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4",
"xterm": "^5.3.0"
}, },
"devDependencies": { "devDependencies": {
"ajv": "^8.17.1", "ajv": "^8.17.1",
@ -2829,6 +2831,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": {
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@ -2838,6 +2849,32 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/@istanbuljs/load-nyc-config/node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/@istanbuljs/schema": { "node_modules/@istanbuljs/schema": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
@ -4629,9 +4666,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.12", "version": "8.5.13",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz",
"integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
@ -5033,6 +5070,12 @@
"@xtuc/long": "4.2.2" "@xtuc/long": "4.2.2"
} }
}, },
"node_modules/@xterm/xterm": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==",
"license": "MIT"
},
"node_modules/@xtuc/ieee754": { "node_modules/@xtuc/ieee754": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@ -5294,14 +5337,20 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/argparse": { "node_modules/argparse": {
"version": "1.0.10", "version": "0.1.16",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"sprintf-js": "~1.0.2" "underscore": "~1.7.0",
"underscore.string": "~2.4.0"
} }
}, },
"node_modules/argparse/node_modules/underscore": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",
"integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA=="
},
"node_modules/aria-query": { "node_modules/aria-query": {
"version": "5.1.3", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
@ -5953,18 +6002,6 @@
"ms": "2.0.0" "ms": "2.0.0"
} }
}, },
"node_modules/body-parser/node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/body-parser/node_modules/ms": { "node_modules/body-parser/node_modules/ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@ -6155,9 +6192,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001676", "version": "1.0.30001677",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz",
"integrity": "sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==", "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -6429,51 +6466,6 @@
"codegen": "lib/codegen-cli.js" "codegen": "lib/codegen-cli.js"
} }
}, },
"node_modules/codegen/node_modules/argparse": {
"version": "0.1.16",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz",
"integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==",
"license": "MIT",
"dependencies": {
"underscore": "~1.7.0",
"underscore.string": "~2.4.0"
}
},
"node_modules/codegen/node_modules/argparse/node_modules/underscore": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",
"integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA=="
},
"node_modules/codegen/node_modules/esprima": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
"integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/codegen/node_modules/js-yaml": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.1.0.tgz",
"integrity": "sha512-AgPExLjC+sVh3GLVZdoTprN9oKoF911GFq0CMs8XVXPyfOfelpH9+NKGAn0NKqt9g38/5nPHqBOD8ObqhoSQ6Q==",
"license": "MIT",
"dependencies": {
"argparse": "~ 0.1.11",
"esprima": "~ 1.0.2"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/codegen/node_modules/underscore": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
"integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ=="
},
"node_modules/collect-v8-coverage": { "node_modules/collect-v8-coverage": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
@ -7943,6 +7935,19 @@
"source-map": "~0.6.1" "source-map": "~0.6.1"
} }
}, },
"node_modules/escodegen/node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/escodegen/node_modules/source-map": { "node_modules/escodegen/node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@ -8551,16 +8556,15 @@
} }
}, },
"node_modules/esprima": { "node_modules/esprima": {
"version": "4.0.1", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==",
"license": "BSD-2-Clause",
"bin": { "bin": {
"esparse": "bin/esparse.js", "esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js" "esvalidate": "bin/esvalidate.js"
}, },
"engines": { "engines": {
"node": ">=4" "node": ">=0.4.0"
} }
}, },
"node_modules/esquery": { "node_modules/esquery": {
@ -9972,12 +9976,12 @@
} }
}, },
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.6.3", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0" "safer-buffer": ">= 2.1.2 < 3"
}, },
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -10132,12 +10136,12 @@
} }
}, },
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {
"version": "2.2.0", "version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 10" "node": ">= 0.10"
} }
}, },
"node_modules/is-arguments": { "node_modules/is-arguments": {
@ -11710,13 +11714,13 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/js-yaml": { "node_modules/js-yaml": {
"version": "3.14.1", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.1.0.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "integrity": "sha512-AgPExLjC+sVh3GLVZdoTprN9oKoF911GFq0CMs8XVXPyfOfelpH9+NKGAn0NKqt9g38/5nPHqBOD8ObqhoSQ6Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^1.0.7", "argparse": "~ 0.1.11",
"esprima": "^4.0.0" "esprima": "~ 1.0.2"
}, },
"bin": { "bin": {
"js-yaml": "bin/js-yaml.js" "js-yaml": "bin/js-yaml.js"
@ -11857,6 +11861,12 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/jsonpath/node_modules/underscore": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz",
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==",
"license": "MIT"
},
"node_modules/jsonpointer": { "node_modules/jsonpointer": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
@ -14443,15 +14453,6 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/proxy-addr/node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"license": "MIT",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/psl": { "node_modules/psl": {
"version": "1.9.0", "version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@ -14561,18 +14562,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/raw-body/node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react": { "node_modules/react": {
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
@ -15801,6 +15790,18 @@
"webpack": "^5.0.0" "webpack": "^5.0.0"
} }
}, },
"node_modules/source-map-loader/node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": { "node_modules/source-map-support": {
"version": "0.5.21", "version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
@ -15928,6 +15929,19 @@
"source-map": "~0.6.1" "source-map": "~0.6.1"
} }
}, },
"node_modules/static-eval/node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/static-eval/node_modules/estraverse": { "node_modules/static-eval/node_modules/estraverse": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
@ -16481,6 +16495,15 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/svgo/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/svgo/node_modules/chalk": { "node_modules/svgo/node_modules/chalk": {
"version": "2.4.2", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
@ -16569,6 +16592,19 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/svgo/node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/svgo/node_modules/has-flag": { "node_modules/svgo/node_modules/has-flag": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@ -16578,6 +16614,19 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/svgo/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/svgo/node_modules/nth-check": { "node_modules/svgo/node_modules/nth-check": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@ -17145,10 +17194,9 @@
} }
}, },
"node_modules/underscore": { "node_modules/underscore": {
"version": "1.12.1", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", "integrity": "sha512-z4o1fvKUojIWh9XuaVLUDdf86RQiq13AC1dmHbTpoyuu+bquHms76v16CjycCbec87J7z0k//SiQVk0sMdFmpQ=="
"license": "MIT"
}, },
"node_modules/underscore.string": { "node_modules/underscore.string": {
"version": "2.4.0", "version": "2.4.0",
@ -17572,6 +17620,15 @@
} }
} }
}, },
"node_modules/webpack-dev-server/node_modules/ipaddr.js": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
"integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==",
"license": "MIT",
"engines": {
"node": ">= 10"
}
},
"node_modules/webpack-dev-server/node_modules/ws": { "node_modules/webpack-dev-server/node_modules/ws": {
"version": "8.18.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
@ -17743,18 +17800,6 @@
"iconv-lite": "0.4.24" "iconv-lite": "0.4.24"
} }
}, },
"node_modules/whatwg-encoding/node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/whatwg-fetch": { "node_modules/whatwg-fetch": {
"version": "3.6.20", "version": "3.6.20",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
@ -18254,6 +18299,13 @@
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/xterm": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
"integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==",
"deprecated": "This package is now deprecated. Move to @xterm/xterm instead.",
"license": "MIT"
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@ -10,13 +10,15 @@
"@testing-library/jest-dom": "^5.17.0", "@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"@xterm/xterm": "^5.5.0",
"codegen": "^0.1.0", "codegen": "^0.1.0",
"eslint-plugin-react": "^7.37.1", "eslint-plugin-react": "^7.37.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-router-dom": "^6.27.0", "react-router-dom": "^6.27.0",
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4",
"xterm": "^5.3.0"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

View File

@ -5,6 +5,7 @@ import Settings from './Settings/SettingsMain'
import Dashboard from './Dashboard/DashboardMain' import Dashboard from './Dashboard/DashboardMain'
import './App.css' import './App.css'
import useToken from './core/useToken'; import useToken from './core/useToken';
import Terminal from './Terminal/TerminalPage'
function App() { function App() {
@ -22,6 +23,7 @@ function App() {
{/* <Route path="/dashboard/configuration" element={<Settings />} /> {/* <Route path="/dashboard/configuration" element={<Settings />} />
<Route path="/dashboard/users" element={<Users />} /> <Route path="/dashboard/users" element={<Users />} />
<Route path="/dashboard/reports" element={<Reports />} /> */} <Route path="/dashboard/reports" element={<Reports />} /> */}
<Route path="/dashboard/console" element={<Terminal/>} />
<Route path="/settings" element={<Settings/>} /> <Route path="/settings" element={<Settings/>} />
</Routes> </Routes>
</Router> </Router>

View File

@ -21,11 +21,11 @@ import ConstructionOutlinedIcon from '@mui/icons-material/ConstructionOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined'; import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined'; import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined'; import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import MenuIcon from '@mui/icons-material/Menu';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined'; import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import { ThemeProvider } from '@mui/material/styles'; import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme'; import theme from '../theme';
import deleteToken from '../core/deleteToken'; import deleteToken from '../core/deleteToken';
import {SystemMon, WebsiteAvailability} from '../widgets/WidgetsStatistics'
const drawerWidth = 240; const drawerWidth = 240;
@ -56,17 +56,8 @@ export default function DashboardMain() {
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}> <Box sx={{ display: 'flex' }}>
<CssBaseline /> <CssBaseline />
<AppBar position="fixed" sx={{ zIndex: (theme) => theme.zIndex.drawer + 1, width: `calc(100% - ${open ? drawerWidth : 0}px)`, ml: `${open ? drawerWidth : 0}px` }}> <AppBar position="fixed" sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}>
<Toolbar> <Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawer}
edge="start"
sx={{ marginRight: 2 }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}> <Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
Admin Dashboard Admin Dashboard
</Typography> </Typography>
@ -82,6 +73,10 @@ export default function DashboardMain() {
open={openMenu} open={openMenu}
onClose={handleMenuClose} onClose={handleMenuClose}
> >
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/dashboard'; }}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Dashboard
</MenuItem>
<MenuItem onClick={handleMenuClose}> <MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} /> <AccountCircleIcon sx={{ marginRight: 2 }} />
Profile Profile
@ -115,14 +110,12 @@ export default function DashboardMain() {
boxSizing: 'border-box', boxSizing: 'border-box',
}, },
}} }}
variant="persistent" variant="permanent"
anchor="left" anchor="left"
open={open}
> >
<Divider /> <Divider />
<List> <List>
<ListItem button key="Dashboard"> <ListItem button key="Dashboard" onClick={() => window.location.href = '/dashboard'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/> <DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Dashboard" sx={{ color: '#FFFFFF' }} /> <ListItemText primary="Dashboard" sx={{ color: '#FFFFFF' }} />
</ListItem> </ListItem>
@ -138,7 +131,7 @@ export default function DashboardMain() {
<ConstructionOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/> <ConstructionOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Server Configuration" sx={{ color: '#FFFFFF' }} /> <ListItemText primary="Server Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem> </ListItem>
<ListItem button key="Terminal"> <ListItem button key="Terminal" onClick={() => window.location.href = '/dashboard/console'}>
<TerminalOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/> <TerminalOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Terminal" sx={{ color: '#FFFFFF' }} /> <ListItemText primary="Terminal" sx={{ color: '#FFFFFF' }} />
</ListItem> </ListItem>
@ -151,9 +144,10 @@ export default function DashboardMain() {
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }} sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
> >
<Toolbar /> <Toolbar />
<Typography paragraph> <Box sx={{ display: 'flex', gap: 3 }}>
Welcome to the Dashboard! <SystemMon/>
</Typography> <WebsiteAvailability/>
</Box>
</Box> </Box>
</Box> </Box>
</ThemeProvider> </ThemeProvider>

View File

@ -17,9 +17,7 @@ import {
import PeopleIcon from '@mui/icons-material/PeopleOutline'; import PeopleIcon from '@mui/icons-material/PeopleOutline';
import DashboardIcon from '@mui/icons-material/DashboardOutlined'; import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import BarChartIcon from '@mui/icons-material/BarChartOutlined'; import BarChartIcon from '@mui/icons-material/BarChartOutlined';
import ConstructionOutlinedIcon from '@mui/icons-material/ConstructionOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined'; import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined'; import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import MenuIcon from '@mui/icons-material/Menu'; import MenuIcon from '@mui/icons-material/Menu';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined'; import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
@ -29,7 +27,7 @@ import deleteToken from '../core/deleteToken';
const drawerWidth = 240; const drawerWidth = 240;
export default function DashboardMain() { export default function SettingsMain() {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [anchorEl, setAnchorEl] = useState(null); const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl); const openMenu = Boolean(anchorEl);
@ -82,6 +80,10 @@ export default function DashboardMain() {
open={openMenu} open={openMenu}
onClose={handleMenuClose} onClose={handleMenuClose}
> >
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/dashboard'; }}>
<DashboardIcon sx={{ marginRight: 2 }} />
Dashboard
</MenuItem>
<MenuItem onClick={handleMenuClose}> <MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} /> <AccountCircleIcon sx={{ marginRight: 2 }} />
Profile Profile

View File

@ -0,0 +1,188 @@
import React, { useState } from 'react';
import {
Box,
ListItem,
ListItemText,
List,
Drawer,
IconButton,
Divider,
CssBaseline,
AppBar,
Toolbar,
Typography,
Menu,
MenuItem,
} from '@mui/material';
import PeopleIcon from '@mui/icons-material/PeopleOutline';
import DashboardIcon from '@mui/icons-material/DashboardOutlined';
import BarChartIcon from '@mui/icons-material/PieChartOutlined';
import ConstructionOutlinedIcon from '@mui/icons-material/ConstructionOutlined';
import SettingsIcon from '@mui/icons-material/SettingsOutlined';
import TerminalOutlinedIcon from '@mui/icons-material/TerminalOutlined';
import LogoutIcon from '@mui/icons-material/LogoutOutlined';
import MenuIcon from '@mui/icons-material/Menu';
import AccountCircleIcon from '@mui/icons-material/AccountCircleOutlined';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
import deleteToken from '../core/deleteToken';
import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
const drawerWidth = 240;
export default function TerminalPage() {
const [open, setOpen] = useState(false);
const [anchorEl, setAnchorEl] = useState(null);
const openMenu = Boolean(anchorEl);
const handleDrawer = () => {
if(open === false){
setOpen(true);
}
else{
setOpen(false);
}
};
const handleMenuClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}>
<Toolbar>
<Typography variant="h6" noWrap sx={{ flexGrow: 1 }}>
Admin Dashboard
</Typography>
<IconButton
color="inherit"
onClick={handleMenuClick}
sx={{ transform: 'scale(1.2)' }}
>
<AccountCircleIcon />
</IconButton>
<Menu
anchorEl={anchorEl}
open={openMenu}
onClose={handleMenuClose}
>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
Profile
</MenuItem>
<MenuItem onClick={handleMenuClose}>
<AccountCircleIcon sx={{ marginRight: 2 }} />
My account
</MenuItem>
<MenuItem onClick={() => { handleMenuClose(); window.location.href = '/settings'; }}>
<SettingsIcon sx={{ marginRight: 2 }} />
Settings
</MenuItem>
<MenuItem onClick={() => {
handleMenuClose();
deleteToken();
window.location.reload();
}}>
<LogoutIcon sx={{ marginRight: 2 }} />
Logout
</MenuItem>
</Menu>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
bgcolor: 'secondary.main',
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Divider />
<List>
<ListItem button key="Dashboard" onClick={() => window.location.href = '/dashboard'}>
<DashboardIcon sx={{ marginRight: 2, color: '#FFFFFF'}}/>
<ListItemText primary="Dashboard" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Users">
<PeopleIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Users" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Reports">
<BarChartIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Reports" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Server Configuration">
<ConstructionOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Server Configuration" sx={{ color: '#FFFFFF' }} />
</ListItem>
<ListItem button key="Terminal" onClick={() => window.location.href = '/dashboard/console'}>
<TerminalOutlinedIcon sx={{ marginRight: 2, color: '#FFFFFF' }}/>
<ListItemText primary="Terminal" sx={{ color: '#FFFFFF' }} />
</ListItem>
</List>
</Drawer>
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
>
<Toolbar />
<Box
id="terminal-container"
ref={(ref) => {
if (ref && !ref.hasChildNodes()) {
const term = new Terminal({
cursorBlink: true,
fontSize: 14,
fontFamily: 'Cascadia Code, Consolas, monospace',
theme: {
background: '#012456', // PowerShell blue background
foreground: '#EEEDF0', // PowerShell text color
cursor: '#EEEDF0'
}
});
term.open(ref);
term.write('Windows PowerShell\r\n');
term.write('Copyright (C) Microsoft Corporation. All rights reserved.\r\n\r\n');
term.write('PS C:\\Users\\Admin> ');
term.onKey(e => {
const char = e.key;
if (char === '\r') { // Enter key
term.write('\r\nPS C:\\Users\\Admin> ');
} else {
term.write(char);
}
});
}
}}
sx={{
width: '100%',
height: '500px',
backgroundColor: '#012456', // PowerShell blue background
borderRadius: '4px',
padding: '8px'
}}
/>
</Box>
</Box>
</ThemeProvider>
);
}

BIN
src/assets/LCSA_Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -3,13 +3,17 @@ import { createTheme } from '@mui/material/styles';
const theme = createTheme({ const theme = createTheme({
palette: { palette: {
primary: { primary: {
main: '#4e00ba', main: '#00523f',
}, },
secondary: { secondary: {
main: '#390087' main: '#003327'
},
warning: {
main: '#520013'
} }
}, },
}); });
export default theme;
export default theme;

View File

@ -0,0 +1,185 @@
import React, { useState, useEffect } from 'react';
import {
Box,
Typography,
CircularProgress,
} from '@mui/material';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../theme';
export const SystemMon = () => {
const [cpuUsage, setCpuUsage] = useState(0);
const [ramUsage, setRamUsage] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
// Симуляция получения данных об использовании CPU и RAM
setCpuUsage(Math.floor(Math.random() * 100));
setRamUsage(Math.floor(Math.random() * 100));
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<ThemeProvider theme={theme}>
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
p: 3,
bgcolor: 'background.paper',
borderRadius: 2,
boxShadow: 3,
width: '500px'
}}>
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
System Monitor
</Typography>
<Box sx={{ display: 'flex', gap: 4, width: '100%', justifyContent: 'center' }}>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<Typography variant="subtitle1" sx={{ mb: 1, color: 'text.secondary' }}>
CPU
</Typography>
<Box sx={{ position: 'relative', display: 'inline-flex' }}>
<CircularProgress
variant="determinate"
value={cpuUsage}
size={80}
thickness={4}
sx={{ color: theme.palette.primary.main }}
/>
<Box sx={{
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{cpuUsage}%
</Typography>
</Box>
</Box>
</Box>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<Typography variant="subtitle1" sx={{ mb: 1, color: 'text.secondary' }}>
RAM
</Typography>
<Box sx={{ position: 'relative', display: 'inline-flex' }}>
<CircularProgress
variant="determinate"
value={ramUsage}
size={80}
thickness={4}
sx={{ color: theme.palette.secondary.main }}
/>
<Box sx={{
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
{ramUsage}%
</Typography>
</Box>
</Box>
</Box>
</Box>
</Box>
</ThemeProvider>
);
};
export const WebsiteAvailability = () => {
return (
<ThemeProvider theme={theme}>
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
p: 3,
bgcolor: 'background.paper',
borderRadius: 2,
boxShadow: 3,
width: '500px'
}}>
<Typography variant="h5" sx={{ mb: 3, color: 'primary.main' }}>
Services Avability
</Typography>
<Box sx={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center', }}>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<Typography variant="subtitle1" sx={{ mb: 1, color: 'text.secondary' }}>
Uptime
</Typography>
<Box sx={{ position: 'relative', display: 'inline-flex' }}>
<CircularProgress
variant="determinate"
value={99.9}
size={80}
thickness={4}
sx={{ color: theme.palette.primary.main }}
/>
<Box sx={{
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
99.9%
</Typography>
</Box>
</Box>
</Box>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
<Typography variant="subtitle1" sx={{ mb: 1, color: 'text.secondary' }}>
Response Time
</Typography>
<Box sx={{ position: 'relative', display: 'inline-flex' }}>
<CircularProgress
variant="determinate"
value={85}
size={80}
thickness={4}
sx={{ color: theme.palette.warning.main }}
/>
<Box sx={{
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'absolute',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<Typography variant="caption" sx={{ fontWeight: 'bold' }}>
85ms
</Typography>
</Box>
</Box>
</Box>
</Box>
</Box>
</ThemeProvider>
);
};