Compare commits
2 Commits
1cf1ac5992
...
9ba64c71d5
| Author | SHA1 | Date |
|---|---|---|
|
|
9ba64c71d5 | |
|
|
afc3cec846 |
|
|
@ -1,73 +0,0 @@
|
||||||
pipeline {
|
|
||||||
agent any
|
|
||||||
environment {
|
|
||||||
REGISTRY_NAME = 'registry.entcor/trust-module'
|
|
||||||
IMAGE_NAME = "trust-module-frontend"
|
|
||||||
GITEA_REPOSITORY_URL = "http://git.entcor/api/v1/repos/"
|
|
||||||
}
|
|
||||||
stages {
|
|
||||||
stage ('Initialize variables') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
env.IMAGE_TAG = sh(script: "git describe --tags --abbrev=0", returnStdout: true).trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ('Build docker image') {
|
|
||||||
when {
|
|
||||||
expression { env.CHANGE_BRANCH?.startsWith('rc') }
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def image = docker.build("${env.IMAGE_NAME}:${env.IMAGE_TAG}")
|
|
||||||
sh "docker tag ${env.IMAGE_NAME}:${env.IMAGE_TAG} ${env.REGISTRY_NAME}/${env.IMAGE_NAME}:${env.IMAGE_TAG}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ('Push docker image to registry') {
|
|
||||||
when {
|
|
||||||
expression { env.CHANGE_BRANCH?.startsWith('rc') }
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
docker.withRegistry('https://registry.entcor/harbor/', 'harbor-credentials-id') {
|
|
||||||
docker.image("${env.REGISTRY_NAME}/${env.IMAGE_NAME}:${env.IMAGE_TAG}").push()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
post {
|
|
||||||
always {
|
|
||||||
script {
|
|
||||||
echo "Cleaning up workspace..."
|
|
||||||
sh "rm -rf ${env.WORKSPACE}/package/ || true"
|
|
||||||
sh "rm -rf ${env.WORKSPACE}/rc/ || true"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
success {
|
|
||||||
script {
|
|
||||||
if (env.CHANGE_BRANCH?.startsWith('rc')) {
|
|
||||||
echo "Attempting to merge PR ${env.CHANGE_ID} into master..."
|
|
||||||
withCredentials([usernamePassword(credentialsId: 'gitea_creds', usernameVariable: 'GITEA_USER', passwordVariable: 'GITEA_PASS')]) {
|
|
||||||
def prId = env.CHANGE_ID
|
|
||||||
sh """
|
|
||||||
curl -X POST \
|
|
||||||
-u "${GITEA_USER}:${GITEA_PASS}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"do":"merge"}' \
|
|
||||||
http://git.entcor/api/v1/repos/DmitriyA/trust-module-frontend/pulls/${prId}/merge
|
|
||||||
"""
|
|
||||||
echo "PR ${prId} merged successfully into master!"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
failure {
|
|
||||||
echo "Pipeline failed. Check the logs for details."
|
|
||||||
}
|
|
||||||
aborted {
|
|
||||||
echo "Pipeline was aborted."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,12 +8,7 @@
|
||||||
"name": "trust-module",
|
"name": "trust-module",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.9",
|
|
||||||
"chart.js": "^4.0.0",
|
|
||||||
"chartjs-adapter-date-fns": "^3.0.0",
|
|
||||||
"d3": "^7.9.0",
|
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-chartjs-2": "^5.0.0",
|
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^18.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -1010,11 +1005,6 @@
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@kurkle/color": {
|
|
||||||
"version": "0.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
|
||||||
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.32.1",
|
"version": "4.32.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.1.tgz",
|
||||||
|
|
@ -1597,11 +1587,6 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/asynckit": {
|
|
||||||
"version": "0.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
|
||||||
},
|
|
||||||
"node_modules/available-typed-arrays": {
|
"node_modules/available-typed-arrays": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||||
|
|
@ -1618,16 +1603,6 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
|
||||||
"version": "1.7.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
|
||||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
|
||||||
"dependencies": {
|
|
||||||
"follow-redirects": "^1.15.6",
|
|
||||||
"form-data": "^4.0.0",
|
|
||||||
"proxy-from-env": "^1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
|
|
@ -1702,6 +1677,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
|
||||||
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
|
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
|
@ -1776,26 +1752,6 @@
|
||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/chart.js": {
|
|
||||||
"version": "4.4.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz",
|
|
||||||
"integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==",
|
|
||||||
"dependencies": {
|
|
||||||
"@kurkle/color": "^0.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"pnpm": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/chartjs-adapter-date-fns": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"chart.js": ">=2.8.0",
|
|
||||||
"date-fns": ">=2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
|
@ -1816,25 +1772,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/combined-stream": {
|
|
||||||
"version": "1.0.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
|
||||||
"dependencies": {
|
|
||||||
"delayed-stream": "~1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/commander": {
|
|
||||||
"version": "7.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
|
||||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/concat-map": {
|
"node_modules/concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
|
|
@ -1871,376 +1808,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/d3": {
|
|
||||||
"version": "7.9.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
|
|
||||||
"integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-array": "3",
|
|
||||||
"d3-axis": "3",
|
|
||||||
"d3-brush": "3",
|
|
||||||
"d3-chord": "3",
|
|
||||||
"d3-color": "3",
|
|
||||||
"d3-contour": "4",
|
|
||||||
"d3-delaunay": "6",
|
|
||||||
"d3-dispatch": "3",
|
|
||||||
"d3-drag": "3",
|
|
||||||
"d3-dsv": "3",
|
|
||||||
"d3-ease": "3",
|
|
||||||
"d3-fetch": "3",
|
|
||||||
"d3-force": "3",
|
|
||||||
"d3-format": "3",
|
|
||||||
"d3-geo": "3",
|
|
||||||
"d3-hierarchy": "3",
|
|
||||||
"d3-interpolate": "3",
|
|
||||||
"d3-path": "3",
|
|
||||||
"d3-polygon": "3",
|
|
||||||
"d3-quadtree": "3",
|
|
||||||
"d3-random": "3",
|
|
||||||
"d3-scale": "4",
|
|
||||||
"d3-scale-chromatic": "3",
|
|
||||||
"d3-selection": "3",
|
|
||||||
"d3-shape": "3",
|
|
||||||
"d3-time": "3",
|
|
||||||
"d3-time-format": "4",
|
|
||||||
"d3-timer": "3",
|
|
||||||
"d3-transition": "3",
|
|
||||||
"d3-zoom": "3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-array": {
|
|
||||||
"version": "3.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
|
|
||||||
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
|
|
||||||
"dependencies": {
|
|
||||||
"internmap": "1 - 2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-axis": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-brush": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-dispatch": "1 - 3",
|
|
||||||
"d3-drag": "2 - 3",
|
|
||||||
"d3-interpolate": "1 - 3",
|
|
||||||
"d3-selection": "3",
|
|
||||||
"d3-transition": "3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-chord": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-path": "1 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-color": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-contour": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-array": "^3.2.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-delaunay": {
|
|
||||||
"version": "6.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
|
|
||||||
"integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
|
|
||||||
"dependencies": {
|
|
||||||
"delaunator": "5"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-dispatch": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-drag": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-dispatch": "1 - 3",
|
|
||||||
"d3-selection": "3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-dsv": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"commander": "7",
|
|
||||||
"iconv-lite": "0.6",
|
|
||||||
"rw": "1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"csv2json": "bin/dsv2json.js",
|
|
||||||
"csv2tsv": "bin/dsv2dsv.js",
|
|
||||||
"dsv2dsv": "bin/dsv2dsv.js",
|
|
||||||
"dsv2json": "bin/dsv2json.js",
|
|
||||||
"json2csv": "bin/json2dsv.js",
|
|
||||||
"json2dsv": "bin/json2dsv.js",
|
|
||||||
"json2tsv": "bin/json2dsv.js",
|
|
||||||
"tsv2csv": "bin/dsv2dsv.js",
|
|
||||||
"tsv2json": "bin/dsv2json.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-ease": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-fetch": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-dsv": "1 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-force": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-dispatch": "1 - 3",
|
|
||||||
"d3-quadtree": "1 - 3",
|
|
||||||
"d3-timer": "1 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-format": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-geo": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-array": "2.5.0 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-hierarchy": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-interpolate": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-color": "1 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-path": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-polygon": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-quadtree": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-random": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-scale": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-array": "2.10.0 - 3",
|
|
||||||
"d3-format": "1 - 3",
|
|
||||||
"d3-interpolate": "1.2.0 - 3",
|
|
||||||
"d3-time": "2.1.1 - 3",
|
|
||||||
"d3-time-format": "2 - 4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-scale-chromatic": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-color": "1 - 3",
|
|
||||||
"d3-interpolate": "1 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-selection": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-shape": {
|
|
||||||
"version": "3.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
|
|
||||||
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-path": "^3.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-time": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-array": "2 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-time-format": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-time": "1 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-timer": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-transition": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-color": "1 - 3",
|
|
||||||
"d3-dispatch": "1 - 3",
|
|
||||||
"d3-ease": "1 - 3",
|
|
||||||
"d3-interpolate": "1 - 3",
|
|
||||||
"d3-timer": "1 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"d3-selection": "2 - 3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/d3-zoom": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
|
|
||||||
"dependencies": {
|
|
||||||
"d3-dispatch": "1 - 3",
|
|
||||||
"d3-drag": "2 - 3",
|
|
||||||
"d3-interpolate": "1 - 3",
|
|
||||||
"d3-selection": "2 - 3",
|
|
||||||
"d3-transition": "2 - 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/data-view-buffer": {
|
"node_modules/data-view-buffer": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
|
||||||
|
|
@ -2295,16 +1862,6 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/date-fns": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
|
|
||||||
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
|
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/kossnocorp"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
|
||||||
|
|
@ -2366,22 +1923,6 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/delaunator": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
|
|
||||||
"dependencies": {
|
|
||||||
"robust-predicates": "^3.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/delayed-stream": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/doctrine": {
|
"node_modules/doctrine": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||||
|
|
@ -2399,6 +1940,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.1",
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
|
@ -2486,6 +2028,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -2495,6 +2038,7 @@
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -2532,6 +2076,7 @@
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0"
|
"es-errors": "^1.3.0"
|
||||||
|
|
@ -2544,6 +2089,7 @@
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
|
@ -2929,25 +2475,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
|
||||||
"version": "1.15.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
|
||||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "individual",
|
|
||||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"debug": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/for-each": {
|
"node_modules/for-each": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz",
|
||||||
|
|
@ -2964,20 +2491,6 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
|
||||||
"dependencies": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.8",
|
|
||||||
"es-set-tostringtag": "^2.1.0",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
|
|
@ -2997,6 +2510,7 @@
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
|
@ -3047,6 +2561,7 @@
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
|
||||||
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
|
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"call-bind-apply-helpers": "^1.0.1",
|
"call-bind-apply-helpers": "^1.0.1",
|
||||||
|
|
@ -3071,6 +2586,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dunder-proto": "^1.0.1",
|
"dunder-proto": "^1.0.1",
|
||||||
|
|
@ -3145,6 +2661,7 @@
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -3209,6 +2726,7 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
|
|
@ -3221,6 +2739,7 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"has-symbols": "^1.0.3"
|
"has-symbols": "^1.0.3"
|
||||||
|
|
@ -3236,6 +2755,7 @@
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"function-bind": "^1.1.2"
|
"function-bind": "^1.1.2"
|
||||||
|
|
@ -3244,17 +2764,6 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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==",
|
|
||||||
"dependencies": {
|
|
||||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
|
|
@ -3307,14 +2816,6 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/internmap": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
|
|
||||||
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.5",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||||
|
|
@ -3870,30 +3371,12 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mime-db": {
|
|
||||||
"version": "1.52.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-types": {
|
|
||||||
"version": "2.1.35",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-db": "1.52.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
|
|
@ -4230,11 +3713,6 @@
|
||||||
"react-is": "^16.13.1"
|
"react-is": "^16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/proxy-from-env": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
|
||||||
},
|
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
|
@ -4257,15 +3735,6 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-chartjs-2": {
|
|
||||||
"version": "5.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz",
|
|
||||||
"integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"chart.js": "^4.1.1",
|
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
|
|
@ -4368,11 +3837,6 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/robust-predicates": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
|
|
||||||
},
|
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.32.1",
|
"version": "4.32.1",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.32.1.tgz",
|
||||||
|
|
@ -4412,11 +3876,6 @@
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rw": {
|
|
||||||
"version": "1.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
|
|
||||||
"integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
|
|
||||||
},
|
|
||||||
"node_modules/safe-array-concat": {
|
"node_modules/safe-array-concat": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
|
||||||
|
|
@ -4472,11 +3931,6 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/safer-buffer": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
|
||||||
},
|
|
||||||
"node_modules/scheduler": {
|
"node_modules/scheduler": {
|
||||||
"version": "0.23.2",
|
"version": "0.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,12 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chartjs-adapter-date-fns": "^3.0.0",
|
"chartjs-adapter-date-fns": "^3.0.0",
|
||||||
|
"recharts": "^2.15.1",
|
||||||
"d3": "^7.9.0",
|
"d3": "^7.9.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"chart.js": "^4.0.0",
|
"chart.js": "^4.0.0",
|
||||||
|
"chartjs-chart-box-and-violin-plot": "^4.0.0",
|
||||||
"react-chartjs-2": "^5.0.0",
|
"react-chartjs-2": "^5.0.0",
|
||||||
"axios": "^1.7.9"
|
"axios": "^1.7.9"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Dashboard from "./Components/Dashboard";
|
import Dashboard from "./Components/Layout/Dashboard";
|
||||||
import LoginModal from "./Components/LoginModal"; // Импортируем компонент авторизации
|
import LoginModal from "./Components/UI/LoginModal"; // Импортируем компонент авторизации
|
||||||
import "./Style/LoginModal.css"; // Импортируем стили
|
import "./Style/LoginModal.css"; // Импортируем стили
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { BarChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Bar, ResponsiveContainer } from 'recharts';
|
||||||
|
|
||||||
|
const BarChartComponent = ({ chartData, metricName, metricType, colors }) => {
|
||||||
|
// Преобразуем данные для отображения
|
||||||
|
const data = Object.keys(chartData).map(instance => {
|
||||||
|
const instanceData = chartData[instance].reduce((acc, point) => {
|
||||||
|
if (point.value !== null) {
|
||||||
|
acc[point.quantile] = point.value;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
return { instance, ...instanceData };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Получаем все уникальные квантили
|
||||||
|
const allQuantiles = [...new Set(
|
||||||
|
Object.values(chartData).flat().map(point => point.quantile)
|
||||||
|
)];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>{metricName} ({metricType})</h2>
|
||||||
|
<ResponsiveContainer width="100%" height={400}>
|
||||||
|
<BarChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="instance" />
|
||||||
|
<YAxis />
|
||||||
|
<Tooltip />
|
||||||
|
<Legend />
|
||||||
|
{allQuantiles.map((quantile, index) => (
|
||||||
|
<Bar
|
||||||
|
key={quantile}
|
||||||
|
dataKey={quantile}
|
||||||
|
fill={colors[index % colors.length]}
|
||||||
|
name={`Quantile ${quantile}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BarChartComponent;
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const CounterComponent = ({ value, metricName }) => {
|
||||||
|
return (
|
||||||
|
<div style={{ textAlign: 'center', padding: '20px', border: '1px solid #ccc', borderRadius: '8px', margin: '10px' }}>
|
||||||
|
<h2>{metricName}</h2>
|
||||||
|
<p style={{ fontSize: '48px', fontWeight: 'bold', color: '#3e95cd' }}>{value}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CounterComponent;
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Line, ResponsiveContainer } from 'recharts';
|
||||||
|
|
||||||
|
const LineChartComponent = ({ chartData, metricName, metricType, colors }) => {
|
||||||
|
// Создаем массив уникальных временных меток
|
||||||
|
const allTimes = Object.values(chartData)
|
||||||
|
.flat()
|
||||||
|
.map(point => point.time)
|
||||||
|
.filter((time, index, self) => self.indexOf(time) === index); // Убираем дубликаты
|
||||||
|
|
||||||
|
// Формируем данные для графика
|
||||||
|
const data = allTimes.map(time => {
|
||||||
|
const point = { time };
|
||||||
|
Object.keys(chartData).forEach(key => {
|
||||||
|
const instanceData = chartData[key].find(p => p.time === time);
|
||||||
|
point[key] = instanceData ? instanceData.value : null;
|
||||||
|
});
|
||||||
|
return point;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Processed Data:', data); // Логируем данные для графика
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>{metricName} ({metricType})</h2>
|
||||||
|
<ResponsiveContainer width="100%" height={400}>
|
||||||
|
<LineChart data={data}>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="time" />
|
||||||
|
<YAxis />
|
||||||
|
<Tooltip />
|
||||||
|
<Legend />
|
||||||
|
{Object.keys(chartData).map((key, index) => (
|
||||||
|
<Line
|
||||||
|
key={key}
|
||||||
|
type="monotone"
|
||||||
|
dataKey={key} // Используем уникальный ключ как dataKey
|
||||||
|
stroke={colors[index % colors.length]}
|
||||||
|
name={key}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LineChartComponent;
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { ScatterChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Scatter, ResponsiveContainer } from 'recharts';
|
||||||
|
|
||||||
|
const ScatterChartComponent = ({ chartData, metricName, metricType, colors }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>{metricName} ({metricType})</h2>
|
||||||
|
<ResponsiveContainer width="100%" height={400}>
|
||||||
|
<ScatterChart>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="time" />
|
||||||
|
<YAxis dataKey="value" />
|
||||||
|
<Tooltip />
|
||||||
|
<Legend />
|
||||||
|
{Object.keys(chartData).map((instance, index) => (
|
||||||
|
<Scatter
|
||||||
|
key={instance}
|
||||||
|
data={chartData[instance]}
|
||||||
|
name={instance}
|
||||||
|
fill={colors[index % colors.length]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ScatterChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ScatterChartComponent;
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import { Line } from "react-chartjs-2";
|
|
||||||
import axios from "axios";
|
|
||||||
import {
|
|
||||||
Chart as ChartJS,
|
|
||||||
LineElement,
|
|
||||||
PointElement,
|
|
||||||
LinearScale,
|
|
||||||
CategoryScale,
|
|
||||||
} from "chart.js";
|
|
||||||
import ExpandableInfo from "../Components/ExpandableInfo"
|
|
||||||
|
|
||||||
ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale);
|
|
||||||
|
|
||||||
const GpuTemperatureChart = () => {
|
|
||||||
const chartRef = useRef(null);
|
|
||||||
const [data, setData] = useState({
|
|
||||||
labels: Array(10).fill("").map((_, i) => i), // 20 точек по X
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: "Температура GPU (°C)",
|
|
||||||
data: [], // Начальные значения (например, 50°C)
|
|
||||||
borderColor: "blue",
|
|
||||||
borderWidth: 2,
|
|
||||||
fill: false,
|
|
||||||
cubicInterpolationMode: "monotone", // Сглаживание
|
|
||||||
tension: 0.4, // Делаем линию плавнее
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchData = async () => {
|
|
||||||
try {
|
|
||||||
const response = await axios.get("/data.json"); // Укажите путь к JSON-файлу
|
|
||||||
setData({
|
|
||||||
labels: response.data.labels,
|
|
||||||
datasets: [{ ...data.datasets[0], data: response.data.datasets[0].data }],
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Ошибка загрузки данных:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchData();
|
|
||||||
const interval = setInterval(fetchData, 5000); // Обновляем данные каждые 5 секунд
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Пример данных для меню "Подробнее"
|
|
||||||
const details = [
|
|
||||||
{ label: "Использование", value: " 20%" },
|
|
||||||
{ label: "Оперативная память ГП", value: " 1,2/7,9 ГБ" },
|
|
||||||
{ label: "Общая память ГП", value: " 1,2/7,9 ГБ" },
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-full max-w-2xl mx-auto p-4 flex flex-col">
|
|
||||||
<h2 className="text-xl font-semibold mb-4">График температуры ГП</h2>
|
|
||||||
<Line
|
|
||||||
ref={chartRef}
|
|
||||||
data={data}
|
|
||||||
options={{
|
|
||||||
animation: false, // Отключаем анимацию обновления (чтобы был плавный сдвиг)
|
|
||||||
scales: {
|
|
||||||
x: { display: true },
|
|
||||||
y: { min: 30, max: 80 }, // Ограничиваем Y (например, 30-80°C)
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ExpandableInfo details={details} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default GpuTemperatureChart;
|
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import axios from 'axios';
|
||||||
|
import LineChartComponent from './Components/LineChartComponent';
|
||||||
|
import BarChartComponent from './Components/BarChartComponent';
|
||||||
|
import ScatterChartComponent from './Components/ScatterChartComponent';
|
||||||
|
|
||||||
|
const MAX_POINTS = 20; // Ограничение точек на графике
|
||||||
|
const COLORS = ['#3e95cd', '#8e5ea2', '#3cba9f', '#e8c3b9', '#c45850']; // Фиксированные цвета для линий
|
||||||
|
|
||||||
|
const PrometheusChart = ({ metricName }) => {
|
||||||
|
const [chartData, setChartData] = useState({});
|
||||||
|
const [metricType, setMetricType] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://192.168.2.33:3000/metrics?metric=prometheus_target_metadata_cache_bytes`);
|
||||||
|
const result = response.data;
|
||||||
|
|
||||||
|
// Проверяем структуру данных
|
||||||
|
let metrics;
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
// Если данные пришли в виде массива
|
||||||
|
metrics = result;
|
||||||
|
} else if (result.data && Array.isArray(result.data)) {
|
||||||
|
// Если данные пришли в виде объекта с ключом data
|
||||||
|
metrics = result.data;
|
||||||
|
} else {
|
||||||
|
throw new Error('Invalid data format');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(metrics) || metrics.length === 0) {
|
||||||
|
throw new Error('No metrics data available');
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = metrics[0].type;
|
||||||
|
setMetricType(type);
|
||||||
|
|
||||||
|
if (type === 'summary') {
|
||||||
|
// Обработка данных для summary
|
||||||
|
const newData = metrics.map(m => ({
|
||||||
|
instance: m.instance,
|
||||||
|
quantile: m.quantile,
|
||||||
|
value: m.value
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Группируем данные по instance
|
||||||
|
const groupedData = newData.reduce((acc, point) => {
|
||||||
|
if (!acc[point.instance]) {
|
||||||
|
acc[point.instance] = [];
|
||||||
|
}
|
||||||
|
acc[point.instance].push(point);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
setChartData(groupedData);
|
||||||
|
} else {
|
||||||
|
// Обработка данных для counter, gauge, unknown
|
||||||
|
const newDataPoints = metrics.map(m => ({
|
||||||
|
time: new Date(m.timestamp).toLocaleTimeString(),
|
||||||
|
value: m.value,
|
||||||
|
instance: m.instance,
|
||||||
|
device: m.device || m.scrape_job, // Используем device или scrape_job
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Группируем данные по instance и device/scrape_job
|
||||||
|
setChartData(prevData => {
|
||||||
|
const updatedData = { ...prevData };
|
||||||
|
|
||||||
|
newDataPoints.forEach(point => {
|
||||||
|
const key = `${point.instance}-${point.device}`; // Уникальный ключ
|
||||||
|
if (!updatedData[key]) {
|
||||||
|
updatedData[key] = [];
|
||||||
|
}
|
||||||
|
updatedData[key].push({
|
||||||
|
time: point.time,
|
||||||
|
value: point.value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return updatedData;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching metrics:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchData(); // Вызываем сразу при монтировании
|
||||||
|
const interval = setInterval(fetchData, 5000); // Обновляем каждые 5 секунд
|
||||||
|
return () => clearInterval(interval); // Очищаем интервал при размонтировании
|
||||||
|
}, [metricName]);
|
||||||
|
|
||||||
|
if (!Object.keys(chartData).length) return <p>Loading...</p>;
|
||||||
|
|
||||||
|
const renderChart = () => {
|
||||||
|
switch (metricType) {
|
||||||
|
case 'counter':
|
||||||
|
case 'gauge':
|
||||||
|
return (
|
||||||
|
<LineChartComponent
|
||||||
|
chartData={chartData}
|
||||||
|
metricName={metricName}
|
||||||
|
metricType={metricType}
|
||||||
|
colors={COLORS}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case 'summary':
|
||||||
|
return (
|
||||||
|
<BarChartComponent
|
||||||
|
chartData={chartData}
|
||||||
|
metricName={metricName}
|
||||||
|
metricType={metricType}
|
||||||
|
colors={COLORS}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case 'unknown':
|
||||||
|
return (
|
||||||
|
<ScatterChartComponent
|
||||||
|
chartData={chartData}
|
||||||
|
metricName={metricName}
|
||||||
|
metricType={metricType}
|
||||||
|
colors={COLORS}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return <p>Unsupported metric type</p>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return renderChart();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PrometheusChart;
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { LineChart, XAxis, YAxis, CartesianGrid, Tooltip, Legend, Line, ResponsiveContainer } from 'recharts';
|
||||||
|
|
||||||
|
const MAX_POINTS = 20; // Ограничение точек на графике
|
||||||
|
const COLORS = ['#3e95cd', '#8e5ea2', '#3cba9f', '#e8c3b9', '#c45850']; // Фиксированные цвета для линий
|
||||||
|
|
||||||
|
const PrometheusChart2 = ({ metricName }) => {
|
||||||
|
const [chartData, setChartData] = useState({});
|
||||||
|
const [metricType, setMetricType] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`http://192.168.2.33:3000/metrics?metric=node_network_iface_link`);
|
||||||
|
const metrics = response.data;
|
||||||
|
if (!Array.isArray(metrics) || metrics.length === 0) {
|
||||||
|
throw new Error('No metrics data available');
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = metrics[0].type;
|
||||||
|
setMetricType(type);
|
||||||
|
|
||||||
|
// Обработка данных для counter, gauge, unknown
|
||||||
|
const newDataPoints = metrics.map(m => ({
|
||||||
|
time: new Date(m.timestamp).toLocaleTimeString(),
|
||||||
|
value: m.value,
|
||||||
|
instance: m.instance // Добавляем идентификатор инстанса
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Обновляем данные для каждого инстанса
|
||||||
|
setChartData(prevData => {
|
||||||
|
const updatedData = { ...prevData };
|
||||||
|
|
||||||
|
newDataPoints.forEach(point => {
|
||||||
|
if (!updatedData[point.instance]) {
|
||||||
|
updatedData[point.instance] = [];
|
||||||
|
}
|
||||||
|
// Добавляем новую точку и ограничиваем количество точек
|
||||||
|
updatedData[point.instance] = [...updatedData[point.instance], point].slice(-MAX_POINTS);
|
||||||
|
});
|
||||||
|
|
||||||
|
return updatedData;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching metrics:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchData(); // Вызываем сразу при монтировании
|
||||||
|
const interval = setInterval(fetchData, 5000); // Обновляем каждые 5 секунд
|
||||||
|
return () => clearInterval(interval); // Очищаем интервал при размонтировании
|
||||||
|
}, [metricName]);
|
||||||
|
|
||||||
|
if (!Object.keys(chartData).length) return <p>Loading...</p>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>{metricName} ({metricType})</h2>
|
||||||
|
<ResponsiveContainer width="100%" height={400}>
|
||||||
|
<LineChart>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="time" />
|
||||||
|
<YAxis />
|
||||||
|
<Tooltip />
|
||||||
|
<Legend />
|
||||||
|
{Object.keys(chartData).map((instance, index) => (
|
||||||
|
<Line
|
||||||
|
key={instance}
|
||||||
|
type="monotone"
|
||||||
|
dataKey="value"
|
||||||
|
data={chartData[instance]}
|
||||||
|
name={instance}
|
||||||
|
stroke={COLORS[index % COLORS.length]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PrometheusChart2;
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import { Line } from "react-chartjs-2";
|
|
||||||
import {
|
|
||||||
Chart as ChartJS,
|
|
||||||
LineElement,
|
|
||||||
PointElement,
|
|
||||||
LinearScale,
|
|
||||||
CategoryScale,
|
|
||||||
} from "chart.js";
|
|
||||||
import ExpandableInfo from "../Components/ExpandableInfo"
|
|
||||||
|
|
||||||
ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale);
|
|
||||||
|
|
||||||
const RamUsageChart = () => {
|
|
||||||
const chartRef = useRef(null);
|
|
||||||
const [data, setData] = useState({
|
|
||||||
labels: Array(10).fill("").map((_, i) => i), // 20 точек по X
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: "Загруженность RAM (%)",
|
|
||||||
data: Array(20).fill(50), // Начальные значения (например, 50%)
|
|
||||||
borderColor: "green",
|
|
||||||
borderWidth: 2,
|
|
||||||
fill: false,
|
|
||||||
cubicInterpolationMode: "monotone", // Сглаживание
|
|
||||||
tension: 0.4, // Делаем линию плавнее
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
setData((prevData) => {
|
|
||||||
const newTemp = Math.floor(Math.random() * 20) + 40; // Генерируем новую температуру (50-600°C)
|
|
||||||
const newLabels = [...prevData.labels.slice(1), prevData.labels[prevData.labels.length - 1] + 1]; // Сдвигаем ось X
|
|
||||||
const newDataset = [...prevData.datasets[0].data.slice(1), newTemp]; // Сдвигаем данные влево
|
|
||||||
|
|
||||||
return {
|
|
||||||
labels: newLabels,
|
|
||||||
datasets: [{ ...prevData.datasets[0], data: newDataset }],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}, 1000); // Обновление каждую секунду
|
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Пример данных для меню "Подробнее"
|
|
||||||
const details = [
|
|
||||||
{ label: "Используется", value: " 6,2 ГБ" },
|
|
||||||
{ label: "Доступно", value: " 9,5 ГБ" },
|
|
||||||
{ label: "Выделено", value: " 6,8/18,2 ГБ" },
|
|
||||||
{ label: "Скорость", value: " 3200 МГц" },
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-full max-w-2xl mx-auto p-4 flex flex-col">
|
|
||||||
<h2 className="text-xl font-semibold mb-4">График загруженности ОЗУ</h2>
|
|
||||||
<Line
|
|
||||||
ref={chartRef}
|
|
||||||
data={data}
|
|
||||||
options={{
|
|
||||||
animation: false, // Отключаем анимацию обновления (чтобы был плавный сдвиг)
|
|
||||||
scales: {
|
|
||||||
x: { display: true },
|
|
||||||
y: { min: 0, max: 100 }, // Ограничиваем Y (например, 30-80°C)
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ExpandableInfo details={details} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RamUsageChart;
|
|
||||||
|
|
@ -1,165 +0,0 @@
|
||||||
import React, { useEffect, useState, useRef } from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Line } from 'react-chartjs-2';
|
|
||||||
import {
|
|
||||||
Chart as ChartJS,
|
|
||||||
CategoryScale,
|
|
||||||
LinearScale,
|
|
||||||
PointElement,
|
|
||||||
LineElement,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
Legend,
|
|
||||||
TimeScale,
|
|
||||||
} from 'chart.js';
|
|
||||||
import 'chartjs-adapter-date-fns'; // Импортируем адаптер дат
|
|
||||||
|
|
||||||
// Регистрируем компоненты Chart.js
|
|
||||||
ChartJS.register(
|
|
||||||
CategoryScale,
|
|
||||||
LinearScale,
|
|
||||||
PointElement,
|
|
||||||
LineElement,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
Legend,
|
|
||||||
TimeScale // Регистрируем временную шкалу
|
|
||||||
);
|
|
||||||
|
|
||||||
const NetworkSpeedChart = () => {
|
|
||||||
const [chartData, setChartData] = useState({
|
|
||||||
labels: [],
|
|
||||||
datasets: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const chartRef = useRef(null); // Референс на график
|
|
||||||
|
|
||||||
// Функция для загрузки данных
|
|
||||||
const fetchData = async () => {
|
|
||||||
try {
|
|
||||||
const response = await axios.get('http://192.168.2.33:3000/metrics?metric=zvks_abonents_total');
|
|
||||||
const newData = response.data;
|
|
||||||
|
|
||||||
console.log('New data from backend:', newData); // Проверяем новые данные
|
|
||||||
|
|
||||||
// Обновляем состояние, добавляя новые данные к существующим
|
|
||||||
setChartData((prevChartData) => {
|
|
||||||
// Группируем новые данные по устройству (device)
|
|
||||||
const newGroupedData = newData.reduce((acc, entry) => {
|
|
||||||
const device = entry.device;
|
|
||||||
if (!acc[device]) {
|
|
||||||
acc[device] = [];
|
|
||||||
}
|
|
||||||
acc[device].push(entry);
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
// Создаем новый набор данных
|
|
||||||
const newDatasets = Object.keys(newGroupedData).map((device, index) => {
|
|
||||||
// Находим существующий dataset для этого устройства
|
|
||||||
const existingDataset = prevChartData.datasets.find((dataset) => dataset.label === `Device: ${device}`);
|
|
||||||
|
|
||||||
// Если dataset уже существует, добавляем новые данные к нему
|
|
||||||
if (existingDataset) {
|
|
||||||
return {
|
|
||||||
...existingDataset,
|
|
||||||
data: [
|
|
||||||
...existingDataset.data,
|
|
||||||
...newGroupedData[device].map((entry) => ({
|
|
||||||
x: new Date(entry.timestamp), // Временная метка
|
|
||||||
y: entry.value, // Значение
|
|
||||||
})),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Если dataset не существует, создаем новый
|
|
||||||
return {
|
|
||||||
label: `Device: ${device}`,
|
|
||||||
data: newGroupedData[device].map((entry) => ({
|
|
||||||
x: new Date(entry.timestamp),
|
|
||||||
y: entry.value,
|
|
||||||
})),
|
|
||||||
borderColor: `hsl(${(index * 360) / Object.keys(newGroupedData).length}, 70%, 50%)`,
|
|
||||||
backgroundColor: `hsla(${(index * 360) / Object.keys(newGroupedData).length}, 70%, 50%, 0.2)`,
|
|
||||||
tension: 0.2,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Обновляем labels (метки времени)
|
|
||||||
const newLabels = [
|
|
||||||
...prevChartData.labels,
|
|
||||||
...newData.map((entry) => new Date(entry.timestamp)),
|
|
||||||
];
|
|
||||||
|
|
||||||
return {
|
|
||||||
labels: newLabels,
|
|
||||||
datasets: newDatasets,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Ошибка при загрузке метрик:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Загружаем данные при монтировании компонента и обновляем каждые 5 секунд
|
|
||||||
useEffect(() => {
|
|
||||||
fetchData();
|
|
||||||
const interval = setInterval(fetchData, 5000);
|
|
||||||
|
|
||||||
// Очищаем интервал и уничтожаем график при размонтировании компонента
|
|
||||||
return () => {
|
|
||||||
clearInterval(interval);
|
|
||||||
if (chartRef.current) {
|
|
||||||
chartRef.current.destroy();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Опции графика
|
|
||||||
const options = {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: {
|
|
||||||
position: 'top',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'node_network_receive_bytes_total',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
x: {
|
|
||||||
type: 'time', // Используем временную шкалу
|
|
||||||
time: {
|
|
||||||
unit: 'second', // Единица времени
|
|
||||||
displayFormats: {
|
|
||||||
second: 'HH:mm:ss', // Формат отображения времени
|
|
||||||
},
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Time',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Данные',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
animation: {
|
|
||||||
duration: 1000, // Длительность анимации
|
|
||||||
easing: 'linear', // Тип анимации
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ width: '800px', height: '400px' }}>
|
|
||||||
<Line ref={chartRef} data={chartData} options={options} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NetworkSpeedChart;
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { Line } from 'react-chartjs-2';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Chart as ChartJS, Title, Tooltip, Legend, LineElement, CategoryScale, LinearScale } from 'chart.js';
|
|
||||||
|
|
||||||
// Регистрация компонентов Chart.js
|
|
||||||
ChartJS.register(Title, Tooltip, Legend, LineElement, CategoryScale, LinearScale);
|
|
||||||
|
|
||||||
const SimpleGraph = () => {
|
|
||||||
const [data, setData] = useState([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetchData = async () => {
|
|
||||||
try {
|
|
||||||
// Загружаем данные из файла с использованием axios
|
|
||||||
const response = await axios.get('/data.json'); // Путь должен быть относительно папки public
|
|
||||||
const rawData = response.data;
|
|
||||||
|
|
||||||
// Проверяем, что данные действительно массив
|
|
||||||
if (Array.isArray(rawData)) {
|
|
||||||
const chartData = rawData.map(item => ({
|
|
||||||
timestamp: item.timestamp,
|
|
||||||
value: item.value,
|
|
||||||
}));
|
|
||||||
|
|
||||||
setData(chartData);
|
|
||||||
} else {
|
|
||||||
throw new Error('Ошибка: Данные не являются массивом.');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching data:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchData();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (data.length === 0) return <div>Loading...</div>;
|
|
||||||
|
|
||||||
// Настройки графика
|
|
||||||
const chartOptions = {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
title: {
|
|
||||||
display: true,
|
|
||||||
text: 'Simple Data Graph',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const chartData = {
|
|
||||||
labels: data.map(item => item.timestamp), // Массив меток для оси X
|
|
||||||
datasets: [
|
|
||||||
{
|
|
||||||
label: 'Value',
|
|
||||||
data: data.map(item => item.value), // Массив значений для оси Y
|
|
||||||
borderColor: 'rgb(75, 192, 192)',
|
|
||||||
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
|
||||||
fill: false,
|
|
||||||
tension: 0.1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
return <Line data={chartData} options={chartOptions} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SimpleGraph;
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import SidebarMenu from "./SidebarMenu";
|
|
||||||
import SystemStatusTable from "../Charts/SystemStatusTable";
|
|
||||||
import SystemStatusTableSoftware from "../Charts/SystemStatusTableSoftware";
|
|
||||||
import TreeChart from "./TreeChart";
|
|
||||||
import "../Style/Dashboard.css";
|
|
||||||
import ErrorIndicator from "./ErrorIndicator";
|
|
||||||
import tabContentData from "./tabContent";
|
|
||||||
import menuData from "./menuData.json"; // Загружаем новое меню
|
|
||||||
|
|
||||||
const Dashboard = () => {
|
|
||||||
const [tabs, setTabs] = useState([]);
|
|
||||||
const [activeTab, setActiveTab] = useState("Главная");
|
|
||||||
const [tabContent, setTabContent] = useState({});
|
|
||||||
const [treeData, setTreeData] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setTabContent(tabContentData);
|
|
||||||
setTreeData(menuData); // Теперь menuData - объект, а не массив
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleOpenTab = (id, title) => {
|
|
||||||
if (!tabs.includes(id)) {
|
|
||||||
setTabs([...tabs, id]);
|
|
||||||
}
|
|
||||||
setActiveTab(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCloseTab = (id) => {
|
|
||||||
const newTabs = tabs.filter((tab) => tab !== id);
|
|
||||||
setTabs(newTabs);
|
|
||||||
if (activeTab === id) {
|
|
||||||
setActiveTab(newTabs.length > 0 ? newTabs[newTabs.length - 1] : "Главная");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderTabContent = () => {
|
|
||||||
if (activeTab === "Главная") {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h2>Общий мониторинг</h2>
|
|
||||||
<ErrorIndicator />
|
|
||||||
<SystemStatusTable />
|
|
||||||
<SystemStatusTableSoftware />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (activeTab === "Визуализация") {
|
|
||||||
return <TreeChart data={treeData} onNodeClick={(id, title) => handleOpenTab(id, title)} />;
|
|
||||||
} else {
|
|
||||||
const tabData = tabContent[activeTab];
|
|
||||||
return tabData ? tabData.content : <p>Нет данных</p>;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="dashboard-container">
|
|
||||||
<SidebarMenu onOpenTab={handleOpenTab} />
|
|
||||||
|
|
||||||
<div className="main-content">
|
|
||||||
<div className="tabs">
|
|
||||||
<div
|
|
||||||
className={`tab ${activeTab === "Главная" ? "active" : ""}`}
|
|
||||||
onClick={() => setActiveTab("Главная")}
|
|
||||||
>
|
|
||||||
Главная
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`tab ${activeTab === "Визуализация" ? "active" : ""}`}
|
|
||||||
onClick={() => setActiveTab("Визуализация")}
|
|
||||||
>
|
|
||||||
Визуализация
|
|
||||||
</div>
|
|
||||||
{tabs.map((tab) => (
|
|
||||||
<div
|
|
||||||
key={tab}
|
|
||||||
className={`tab ${activeTab === tab ? "active" : ""}`}
|
|
||||||
onClick={() => setActiveTab(tab)}
|
|
||||||
>
|
|
||||||
{tab}
|
|
||||||
<button
|
|
||||||
className="close-tab"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleCloseTab(tab);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="content">
|
|
||||||
{renderTabContent()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Dashboard;
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import SidebarMenu from "./SidebarMenu";
|
||||||
|
import TreeChart from "../TreeChart/TreeChart";
|
||||||
|
import "../../Style/Dashboard.css";
|
||||||
|
import ErrorIndicator from "../UI/ErrorIndicator";
|
||||||
|
import tabContentData from "../TreeChart/tabContent";
|
||||||
|
import Tabs from "../UI/Tabs";
|
||||||
|
import menuData from "../TreeChart//menuData.json"; // Загружаем новое меню
|
||||||
|
import TableComponent from '../UI/TreeTable';
|
||||||
|
import TreeTable from "../UI/TreeTable";
|
||||||
|
|
||||||
|
|
||||||
|
const Dashboard = () => {
|
||||||
|
const [tabs, setTabs] = useState([]);
|
||||||
|
const [activeTab, setActiveTab] = useState("Главная");
|
||||||
|
const [tabContent, setTabContent] = useState({});
|
||||||
|
const [treeData, setTreeData] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTabContent(tabContentData);
|
||||||
|
setTreeData(menuData);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleOpenTab = (id, title) => {
|
||||||
|
if (!tabs.some((tab) => tab.id === id)) {
|
||||||
|
setTabs([...tabs, { id, title }]);
|
||||||
|
}
|
||||||
|
setActiveTab(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseTab = (id) => {
|
||||||
|
const newTabs = tabs.filter((tab) => tab.id !== id);
|
||||||
|
setTabs(newTabs);
|
||||||
|
if (activeTab === id) {
|
||||||
|
setActiveTab(newTabs.length > 0 ? newTabs[newTabs.length - 1].id : "Главная");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTabContent = () => {
|
||||||
|
if (activeTab === "Главная") {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Общий мониторинг</h2>
|
||||||
|
<ErrorIndicator />
|
||||||
|
<TreeTable data={menuData.items} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (activeTab === "Визуализация") {
|
||||||
|
return <TreeChart data={treeData} onNodeClick={(id, title) => handleOpenTab(id, title)} />;
|
||||||
|
} else {
|
||||||
|
const tabData = tabContent[activeTab];
|
||||||
|
return tabData ? tabData.content : <p>Нет данных</p>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dashboard-container">
|
||||||
|
<SidebarMenu onOpenTab={handleOpenTab} />
|
||||||
|
|
||||||
|
<div className="main-content">
|
||||||
|
<Tabs
|
||||||
|
tabs={tabs}
|
||||||
|
activeTab={activeTab}
|
||||||
|
onTabClick={(id) => setActiveTab(id)}
|
||||||
|
onCloseTab={handleCloseTab}
|
||||||
|
/>
|
||||||
|
<div className="content">
|
||||||
|
{renderTabContent()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Dashboard;
|
||||||
|
|
@ -1,10 +1,24 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import "../Style/SidebarMenu.css";
|
import "../../Style/SidebarMenu.css";
|
||||||
import menuData from "./menuData.json";
|
import menuData from "../TreeChart/menuData.json";
|
||||||
|
|
||||||
|
const getStatusColor = (status) => {
|
||||||
|
switch (status) {
|
||||||
|
case "green":
|
||||||
|
return "#4CAF50"; // Зеленый
|
||||||
|
case "yellow":
|
||||||
|
return "#FFEB3B"; // Желтый
|
||||||
|
case "red":
|
||||||
|
return "#F44336"; // Красный
|
||||||
|
default:
|
||||||
|
return "#3d74c7"; // Белый (или любой другой стандартный цвет)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const MenuItem = ({ item, onSelectItem }) => {
|
const MenuItem = ({ item, onSelectItem }) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const hasChildren = Array.isArray(item.items) && item.items.length > 0;
|
const hasChildren = Array.isArray(item.items) && item.items.length > 0;
|
||||||
|
const backgroundColor = getStatusColor(item.status);
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
|
|
@ -16,7 +30,7 @@ const MenuItem = ({ item, onSelectItem }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="menu-item">
|
<div className="menu-item">
|
||||||
<div onClick={handleClick} className="menu-item-header">
|
<div onClick={handleClick} className="menu-item-header" style={{ backgroundColor }}>
|
||||||
<span>{item.title}</span>
|
<span>{item.title}</span>
|
||||||
{hasChildren && <span>{isOpen ? "▲" : "▼"}</span>}
|
{hasChildren && <span>{isOpen ? "▲" : "▼"}</span>}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
import React, { useState } from "react";
|
|
||||||
|
|
||||||
const Login = ({ onLogin, onClose }) => {
|
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const [password, setPassword] = useState("");
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (username === "admin" && password === "admin") {
|
|
||||||
onLogin(); // Успешная авторизация
|
|
||||||
onClose(); // Закрыть модальное окно
|
|
||||||
} else {
|
|
||||||
setError("Неверный логин или пароль");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="modal-overlay">
|
|
||||||
<div className="modal">
|
|
||||||
<h2>Авторизация</h2>
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div>
|
|
||||||
<label>Логин:</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={username}
|
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>Пароль:</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
value={password}
|
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{error && <p className="error">{error}</p>}
|
|
||||||
<button type="submit">Войти</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Login;
|
|
||||||
|
|
@ -11,7 +11,7 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
d3.select(chartRef.current).selectAll("*").remove();
|
d3.select(chartRef.current).selectAll("*").remove();
|
||||||
|
|
||||||
const width = 928;
|
const width = 928;
|
||||||
const height = 600;
|
const height = 1000;
|
||||||
|
|
||||||
const root = d3.hierarchy(data, (d) => d.items);
|
const root = d3.hierarchy(data, (d) => d.items);
|
||||||
const links = root.links();
|
const links = root.links();
|
||||||
|
|
@ -19,8 +19,8 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
|
|
||||||
const simulation = d3
|
const simulation = d3
|
||||||
.forceSimulation(nodes)
|
.forceSimulation(nodes)
|
||||||
.force("link", d3.forceLink(links).id((d) => d.data.title).distance(80).strength(1)) // Увеличил дистанцию
|
.force("link", d3.forceLink(links).id((d) => d.data.title).distance(80).strength(1))
|
||||||
.force("charge", d3.forceManyBody().strength(-500)) // Увеличил отталкивание узлов
|
.force("charge", d3.forceManyBody().strength(-500))
|
||||||
.force("x", d3.forceX())
|
.force("x", d3.forceX())
|
||||||
.force("y", d3.forceY());
|
.force("y", d3.forceY());
|
||||||
|
|
||||||
|
|
@ -46,9 +46,21 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
.selectAll("circle")
|
.selectAll("circle")
|
||||||
.data(nodes)
|
.data(nodes)
|
||||||
.join("circle")
|
.join("circle")
|
||||||
.attr("fill", (d) => (d.children ? "#555" : "#000"))
|
.attr("fill", (d) => {
|
||||||
|
// Окрашиваем узлы в зависимости от статуса
|
||||||
|
switch (d.data.status) {
|
||||||
|
case "green":
|
||||||
|
return "#4CAF50"; // Зеленый
|
||||||
|
case "yellow":
|
||||||
|
return "#FFEB3B"; // Желтый
|
||||||
|
case "red":
|
||||||
|
return "#F44336"; // Красный
|
||||||
|
default:
|
||||||
|
return "#555"; // Серый по умолчанию
|
||||||
|
}
|
||||||
|
})
|
||||||
.attr("stroke", "#fff")
|
.attr("stroke", "#fff")
|
||||||
.attr("r", 7) // Немного увеличил размер узлов для удобства клика
|
.attr("r", 7)
|
||||||
.call(drag(simulation));
|
.call(drag(simulation));
|
||||||
|
|
||||||
// Добавляем текстовые подписи
|
// Добавляем текстовые подписи
|
||||||
|
|
@ -57,13 +69,13 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
.attr("fill", "#000")
|
.attr("fill", "#000")
|
||||||
.attr("font-family", "Arial")
|
.attr("font-family", "Arial")
|
||||||
.attr("font-size", 12)
|
.attr("font-size", 12)
|
||||||
.attr("pointer-events", "none") // Отключаем обработку событий текста
|
.attr("pointer-events", "none")
|
||||||
.selectAll("text")
|
.selectAll("text")
|
||||||
.data(nodes)
|
.data(nodes)
|
||||||
.join("text")
|
.join("text")
|
||||||
.text((d) => d.data.title)
|
.text((d) => d.data.title)
|
||||||
.attr("dx", 12) // Отодвигаем текст дальше от узла
|
.attr("dx", 12)
|
||||||
.attr("dy", 4) // Немного поднимаем текст
|
.attr("dy", 4);
|
||||||
|
|
||||||
node.append("title").text((d) => d.data.title);
|
node.append("title").text((d) => d.data.title);
|
||||||
|
|
||||||
|
|
@ -85,7 +97,7 @@ const TreeChart = ({ data, onNodeClick }) => {
|
||||||
.attr("cy", (d) => d.y);
|
.attr("cy", (d) => d.y);
|
||||||
|
|
||||||
text
|
text
|
||||||
.attr("x", (d) => d.x + 12) // Смещаем текст правее узла
|
.attr("x", (d) => d.x + 12)
|
||||||
.attr("y", (d) => d.y + 4);
|
.attr("y", (d) => d.y + 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -0,0 +1,225 @@
|
||||||
|
{
|
||||||
|
"title": "Сервис ВКС",
|
||||||
|
"status": "red",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Функциональные задачи",
|
||||||
|
"status": "red",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "system_control",
|
||||||
|
"title": "Контроль системы",
|
||||||
|
"status": "red"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_management",
|
||||||
|
"title": "Система управления",
|
||||||
|
"status": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "conference",
|
||||||
|
"title": "Проведение ВКС",
|
||||||
|
"status": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "backup",
|
||||||
|
"title": "Резервное копирование",
|
||||||
|
"status": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "relay_info",
|
||||||
|
"title": "Ретрансляция информации",
|
||||||
|
"status": "green"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Медиа сервер",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Аппаратное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "media_system_software_1",
|
||||||
|
"title": "Центральный процессор"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "media_system_software_2",
|
||||||
|
"title": "Оперативная память"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "media_system_software_3",
|
||||||
|
"title": "Жесткий диск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "media_system_software_4",
|
||||||
|
"title": "Сетевые адаптеры"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Программное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "media_software_1",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "media_software_2",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "media_software_3",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "media_software_4",
|
||||||
|
"title": "ПО"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Сервер резервного копирования",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Аппаратное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "copy_system_software_1",
|
||||||
|
"title": "Центральный процессор"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "copy_system_software_2",
|
||||||
|
"title": "Оперативная память"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "copy_system_software_3",
|
||||||
|
"title": "Жесткий диск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "copy_system_software_4",
|
||||||
|
"title": "Сетевые адаптеры"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Программное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "copy_software_1",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "copy_software_2",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "copy_software_3",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "copy_software_4",
|
||||||
|
"title": "ПО"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Сервер системы управления",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Аппаратное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "control_system_software_1",
|
||||||
|
"title": "Центральный процессор"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "control_system_software_2",
|
||||||
|
"title": "Оперативная память"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "control_system_software_3",
|
||||||
|
"title": "Жесткий диск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "control_system_software_4",
|
||||||
|
"title": "Сетевые адаптеры"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Программное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "control_software_1",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "control_software_2",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "control_software_3",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "control_software_4",
|
||||||
|
"title": "ПО"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Сервер сбора и ретрансляции информации",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Аппаратное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "system_software_1",
|
||||||
|
"title": "Центральный процессор"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_software_2",
|
||||||
|
"title": "Оперативная память"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_software_3",
|
||||||
|
"title": "Жесткий диск"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_software_4",
|
||||||
|
"title": "Сетевые адаптеры"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Программное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "software_1",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_2",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_3",
|
||||||
|
"title": "ПО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_4",
|
||||||
|
"title": "ПО"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
{
|
||||||
|
"title": "Сервис ВКС",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Функциональные задачи",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Тест",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "test1",
|
||||||
|
"title": "тест2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "test2",
|
||||||
|
"title": "Тест3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_control",
|
||||||
|
"title": "Контроль системы"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "system_management",
|
||||||
|
"title": "Система управления"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "conference",
|
||||||
|
"title": "Проведение ВКС"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "backup",
|
||||||
|
"title": "Резервное копирование"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "relay_info",
|
||||||
|
"title": "Ретрансляция информации"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Аппаратное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "hardware_software_1",
|
||||||
|
"title": "Сервер системы управления"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hardware_software_2",
|
||||||
|
"title": "Сервер системы управления"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hardware_software_3",
|
||||||
|
"title": "Медиа-сервер"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hardware_software_4",
|
||||||
|
"title": "Медиа-сервер"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hardware_software_5",
|
||||||
|
"title": "Медиа-сервер"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hardware_software_6",
|
||||||
|
"title": "Медиа-сервер"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hardware_software_7",
|
||||||
|
"title": "Сервер резервного копирования"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "hardware_software_8",
|
||||||
|
"title": "Сервер сбора и ретрансляции информации"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Программное обеспечение",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "software_1",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_2",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_3",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_4",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_5",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_6",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_7",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "software_8",
|
||||||
|
"title": "БП/ППО"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import React from "react";
|
||||||
|
import PrometheusChart from '../../Charts/PrometheusChart';
|
||||||
|
|
||||||
|
const tabContent = {
|
||||||
|
// Сервис ВКС
|
||||||
|
service1: { title: "Сервис ВКС", content: <div><h2>Сервис ВКС</h2></div> },
|
||||||
|
|
||||||
|
// Функциональные задачи
|
||||||
|
system_control: { title: "Контроль системы", content: <div><h2>Контроль системы</h2><p>Описание контроля.</p></div> },
|
||||||
|
system_management: { title: "Система управления", content: <div><h2>Система управления</h2><p>Описание системы управления.</p></div> },
|
||||||
|
conference: { title: "Проведение ВКС", content: <div><h2>Проведение ВКС</h2><p>Информация о проведении ВКС.</p></div> },
|
||||||
|
backup: { title: "Резервное копирование", content: <div><h2>Резервное копирование</h2><p>Процесс резервного копирования.</p></div> },
|
||||||
|
relay_info: { title: "Ретрансляция информации", content: <div><h2>Ретрансляция информации</h2><p>Детали ретрансляции.</p></div> },
|
||||||
|
|
||||||
|
// Медиа сервер
|
||||||
|
media_system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора медиа сервера.</p></div> },
|
||||||
|
media_system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти медиа сервера.</p></div> },
|
||||||
|
media_system_software_3: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска медиа сервера.</p></div> },
|
||||||
|
media_system_software_4: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров медиа сервера.</p></div> },
|
||||||
|
media_software_1: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><PrometheusChart /></div> },
|
||||||
|
media_software_2: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_3: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
media_software_4: { title: "ПО", content: <div><h2>Программное обеспечение медиа сервера</h2><p>Описание ПО медиа сервера.</p></div> },
|
||||||
|
|
||||||
|
// Сервер резервного копирования
|
||||||
|
copy_system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора сервера резервного копирования.</p></div> },
|
||||||
|
copy_system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти сервера резервного копирования.</p></div> },
|
||||||
|
copy_system_software_3: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска сервера резервного копирования.</p></div> },
|
||||||
|
copy_system_software_4: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров сервера резервного копирования.</p></div> },
|
||||||
|
copy_software_1: { title: "ПО", content: <div><h2>Программное обеспечение сервера резервного копирования</h2><p>Описание ПО сервера резервного копирования.</p></div> },
|
||||||
|
copy_software_2: { title: "ПО", content: <div><h2>Программное обеспечение сервера резервного копирования</h2><p>Описание ПО сервера резервного копирования.</p></div> },
|
||||||
|
copy_software_3: { title: "ПО", content: <div><h2>Программное обеспечение сервера резервного копирования</h2><p>Описание ПО сервера резервного копирования.</p></div> },
|
||||||
|
copy_software_4: { title: "ПО", content: <div><h2>Программное обеспечение сервера резервного копирования</h2><p>Описание ПО сервера резервного копирования.</p></div> },
|
||||||
|
|
||||||
|
// Сервер системы управления
|
||||||
|
control_system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора сервера системы управления.</p></div> },
|
||||||
|
control_system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти сервера системы управления.</p></div> },
|
||||||
|
control_system_software_3: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска сервера системы управления.</p></div> },
|
||||||
|
control_system_software_4: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров сервера системы управления.</p></div> },
|
||||||
|
control_software_1: { title: "ПО", content: <div><h2>Программное обеспечение сервера системы управления</h2><p>Описание ПО сервера системы управления.</p></div> },
|
||||||
|
control_software_2: { title: "ПО", content: <div><h2>Программное обеспечение сервера системы управления</h2><p>Описание ПО сервера системы управления.</p></div> },
|
||||||
|
control_software_3: { title: "ПО", content: <div><h2>Программное обеспечение сервера системы управления</h2><p>Описание ПО сервера системы управления.</p></div> },
|
||||||
|
control_software_4: { title: "ПО", content: <div><h2>Программное обеспечение сервера системы управления</h2><p>Описание ПО сервера системы управления.</p></div> },
|
||||||
|
|
||||||
|
// Сервер сбора и ретрансляции информации
|
||||||
|
system_software_1: { title: "Центральный процессор", content: <div><h2>Центральный процессор</h2><p>Описание центрального процессора сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
system_software_2: { title: "Оперативная память", content: <div><h2>Оперативная память</h2><p>Описание оперативной памяти сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
system_software_3: { title: "Жесткий диск", content: <div><h2>Жесткий диск</h2><p>Описание жесткого диска сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
system_software_4: { title: "Сетевые адаптеры", content: <div><h2>Сетевые адаптеры</h2><p>Описание сетевых адаптеров сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
software_1: { title: "ПО", content: <div><h2>Программное обеспечение сервера сбора и ретрансляции информации</h2><p>Описание ПО сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
software_2: { title: "ПО", content: <div><h2>Программное обеспечение сервера сбора и ретрансляции информации</h2><p>Описание ПО сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
software_3: { title: "ПО", content: <div><h2>Программное обеспечение сервера сбора и ретрансляции информации</h2><p>Описание ПО сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
software_4: { title: "ПО", content: <div><h2>Программное обеспечение сервера сбора и ретрансляции информации</h2><p>Описание ПО сервера сбора и ретрансляции информации.</p></div> },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default tabContent;
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
import React from "react";
|
||||||
|
import NetworkSpeedChart2 from '../../Charts/TestCharts2';
|
||||||
|
import PrometheusChart from '../../Charts/PrometheusChart';
|
||||||
|
import PrometheusChart2 from '../../Charts/PrometheusChart2';
|
||||||
|
|
||||||
|
const tabContent = {
|
||||||
|
service1: { title: "Сервис ВКС", content: <div><h2>Сервис ВКС</h2></div> },
|
||||||
|
system_control: { title: "Контроль системы", content: <div><h2>Контроль системы</h2><p>Описание контроля.</p></div> },
|
||||||
|
system_management: { title: "Система управления", content: <div><h2>Система управления</h2><p>Описание системы управления.</p></div> },
|
||||||
|
conference: { title: "Проведение ВКС", content: <div><h2>Проведение ВКС</h2><p>Информация о проведении ВКС.</p></div> },
|
||||||
|
backup: { title: "Резервное копирование", content: <div><h2>Резервное копирование</h2><p>Процесс резервного копирования.</p></div> },
|
||||||
|
relay_info: { title: "Ретрансляция информации", content: <div><h2>Ретрансляция информации</h2><p>Детали ретрансляции.</p></div> },
|
||||||
|
hardware_software_1: { title: "Сервер системы управления", content: <div><h2>Сервер системы управления</h2><PrometheusChart /></div> },
|
||||||
|
hardware_software_2: { title: "Сервер системы управления", content: <div><h2>Сервер системы управления</h2></div> },
|
||||||
|
hardware_software_3: { title: "Медиа-сервер", content: <div><h2>Медиа-сервер</h2></div> },
|
||||||
|
hardware_software_4: { title: "Медиа-сервер", content: <div><h2>Медиа-сервер</h2></div> },
|
||||||
|
hardware_software_5: { title: "Медиа-сервер", content: <div><h2>Медиа-сервер</h2></div> },
|
||||||
|
hardware_software_6: { title: "Медиа-сервер", content: <div><h2>Медиа-сервер</h2></div> },
|
||||||
|
hardware_software_7: { title: "Сервер резервного копирования", content: <div><h2>Сервер резервного копирования</h2></div> },
|
||||||
|
hardware_software_8: { title: "Сервер сбора и ретрансляции информации", content: <div><h2>Сервер сбора и ретрансляции информации</h2></div> },
|
||||||
|
software_1: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
software_2: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
software_3: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
software_4: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
software_5: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
software_6: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
software_7: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
software_8: { title: "БП/ППО", content: <div><h2>БП/ППО</h2></div> },
|
||||||
|
};
|
||||||
|
|
||||||
|
export default tabContent;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import criticalIcon from "../assets/images/critical.png"; // Красный треугольник
|
import criticalIcon from "../../assets/images/critical.png"; // Красный треугольник
|
||||||
import warningIcon from "../assets/images/warning.png"; // Желтый треугольник
|
import warningIcon from "../../assets/images/warning.png"; // Желтый треугольник
|
||||||
import "../Style/ErrorIndicator.css"; // Подключаем стили
|
import "../../Style/ErrorIndicator.css"; // Подключаем стили
|
||||||
|
|
||||||
const ErrorIndicator = ({ criticalCount, warningCount }) => {
|
const ErrorIndicator = ({ criticalCount, warningCount }) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import Modal from "./Modal";
|
||||||
|
import "../../Style/LoginModal.css";
|
||||||
|
|
||||||
|
const LoginModal = ({ onLogin, onClose }) => {
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
const handleSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (username === "admin" && password === "admin") {
|
||||||
|
onLogin(); // Успешная авторизация
|
||||||
|
onClose(); // Закрыть модальное окно
|
||||||
|
} else {
|
||||||
|
setError("Неверный логин или пароль");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal onClose={onClose}>
|
||||||
|
<h2>Авторизация</h2>
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div>
|
||||||
|
<label>Логин:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Пароль:</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{error && <p className="error">{error}</p>}
|
||||||
|
<button type="submit">Войти</button>
|
||||||
|
</form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoginModal;
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const Modal = ({ children, onClose }) => {
|
||||||
|
return (
|
||||||
|
<div className="modal-overlay">
|
||||||
|
<div className="modal">
|
||||||
|
{children}
|
||||||
|
<button onClick={onClose}>Закрыть</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Modal;
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import React from "react";
|
||||||
|
import "../../Style/common.css"; // Общие стили для табов
|
||||||
|
|
||||||
|
const Tabs = ({ tabs, activeTab, onTabClick, onCloseTab }) => {
|
||||||
|
const handleMouseDown = (e, id) => {
|
||||||
|
// Проверяем, была ли нажата средняя кнопка мыши (button === 1)
|
||||||
|
if (e.button === 1) {
|
||||||
|
e.preventDefault(); // Предотвращаем стандартное поведение (например, прокрутку)
|
||||||
|
onCloseTab(id); // Закрываем вкладку
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="tabs">
|
||||||
|
{/* Всегда отображаемые вкладки */}
|
||||||
|
<div
|
||||||
|
className={`tab ${activeTab === "Главная" ? "active" : ""}`}
|
||||||
|
onClick={() => onTabClick("Главная")}
|
||||||
|
onMouseDown={(e) => handleMouseDown(e, "Главная")} // Добавляем обработчик для СКМ
|
||||||
|
>
|
||||||
|
<span>Главная</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`tab ${activeTab === "Визуализация" ? "active" : ""}`}
|
||||||
|
onClick={() => onTabClick("Визуализация")}
|
||||||
|
onMouseDown={(e) => handleMouseDown(e, "Визуализация")} // Добавляем обработчик для СКМ
|
||||||
|
>
|
||||||
|
<span>Визуализация</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Динамически добавляемые вкладки */}
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<div
|
||||||
|
key={tab.id}
|
||||||
|
className={`tab ${activeTab === tab.id ? "active" : ""}`}
|
||||||
|
onClick={() => onTabClick(tab.id)}
|
||||||
|
onMouseDown={(e) => handleMouseDown(e, tab.id)} // Добавляем обработчик для СКМ
|
||||||
|
>
|
||||||
|
<span>{tab.title}</span>
|
||||||
|
<button
|
||||||
|
className="close-tab"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onCloseTab(tab.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tabs;
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React from "react";
|
||||||
|
import "../../Style/TreeTable.css"; // Подключаем стили
|
||||||
|
|
||||||
|
const TreeTable = ({ data }) => {
|
||||||
|
return (
|
||||||
|
<div className="tree-table">
|
||||||
|
{/* Первый уровень заголовков */}
|
||||||
|
<div className="tree-table-header">
|
||||||
|
{data.map((item, index) => (
|
||||||
|
<div key={index} className="tree-table-column">
|
||||||
|
<div className="tree-table-title">{item.title}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Вложенные элементы */}
|
||||||
|
<div className="tree-table-body">
|
||||||
|
{data.map((item, index) => (
|
||||||
|
<div key={index} className="tree-table-column">
|
||||||
|
{item.items && (
|
||||||
|
<div className="tree-table-items">
|
||||||
|
{item.items.map((child, childIndex) => (
|
||||||
|
<div key={childIndex} className="tree-table-item">
|
||||||
|
{child.title}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TreeTable;
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
{
|
|
||||||
"title": "Сервис ВКС",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"title": "Функциональные задачи",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"id": "system_control",
|
|
||||||
"title": "Контроль системы"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "system_management",
|
|
||||||
"title": "Система управления"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "conference",
|
|
||||||
"title": "Проведение ВКС"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "backup",
|
|
||||||
"title": "Резервное копирование"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "relay_info",
|
|
||||||
"title": "Ретрансляция информации"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Аппаратное ПО",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"id": "hardware_software_1",
|
|
||||||
"title": "ПО1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "hardware_software_2",
|
|
||||||
"title": "ПО2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "hardware_software_3",
|
|
||||||
"title": "ПО3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "hardware_software_4",
|
|
||||||
"title": "ПО4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "hardware_software_5",
|
|
||||||
"title": "ПО5"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import NetworkSpeedChart2 from '../Charts/TestCharts2';
|
|
||||||
|
|
||||||
const tabContent = {
|
|
||||||
service1: { title: "Сервис ВКС", content: <div><h2>Сервис ВКС</h2></div> },
|
|
||||||
system_control: { title: "Контроль системы", content: <div><h2>Контроль системы</h2><p>Описание контроля.</p></div> },
|
|
||||||
system_management: { title: "Система управления", content: <div><h2>Система управления</h2><p>Описание системы управления.</p></div> },
|
|
||||||
conference: { title: "Проведение ВКС", content: <div><h2>Проведение ВКС</h2><p>Информация о проведении ВКС.</p></div> },
|
|
||||||
backup: { title: "Резервное копирование", content: <div><h2>Резервное копирование</h2><p>Процесс резервного копирования.</p></div> },
|
|
||||||
relay_info: { title: "Ретрансляция информации", content: <div><h2>Ретрансляция информации</h2><p>Детали ретрансляции.</p></div> },
|
|
||||||
hardware_software_1: { title: "График скорости сети", content: <div><h2>График скорости сети</h2><NetworkSpeedChart2 /></div> },
|
|
||||||
hardware_software_2: { title: "ПО2", content: <div><h2>ПО2</h2></div> },
|
|
||||||
hardware_software_3: { title: "ПО3", content: <div><h2>ПО3</h2></div> },
|
|
||||||
hardware_software_4: { title: "ПО4", content: <div><h2>ПО4</h2></div> },
|
|
||||||
hardware_software_5: { title: "ПО5", content: <div><h2>ПО5</h2></div> },
|
|
||||||
};
|
|
||||||
|
|
||||||
export default tabContent;
|
|
||||||
|
|
@ -18,53 +18,12 @@
|
||||||
/* Ограничиваем высоту */
|
/* Ограничиваем высоту */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Вкладки */
|
|
||||||
.tabs {
|
|
||||||
display: flex;
|
|
||||||
gap: 5px;
|
|
||||||
padding: 5px;
|
|
||||||
background-color: #222;
|
|
||||||
border-bottom: 2px solid #444;
|
|
||||||
overflow-x: auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background-color: #333;
|
|
||||||
color: white;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 5px 5px 0 0;
|
|
||||||
cursor: pointer;
|
|
||||||
max-width: 250px;
|
|
||||||
/* Ограничиваем максимальную ширину */
|
|
||||||
min-width: 100px;
|
|
||||||
/* Минимальная ширина */
|
|
||||||
flex-shrink: 0;
|
|
||||||
/* Не позволяет вкладкам сжиматься */
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab.active {
|
|
||||||
background-color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-tab {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Контент */
|
/* Контент */
|
||||||
.content {
|
.content {
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 5px rgba(29, 1, 1, 0.521);
|
||||||
}
|
}
|
||||||
|
|
||||||
.default-content {
|
.default-content {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-item {
|
.error-item {
|
||||||
|
|
@ -33,4 +34,5 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
background: white;
|
background: rgb(255, 255, 255);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
.modal label {
|
.modal label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal input {
|
.modal input {
|
||||||
|
|
@ -38,7 +39,8 @@
|
||||||
|
|
||||||
.modal button {
|
.modal button {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
background: #007bff;
|
margin-bottom: 5px;
|
||||||
|
background: #08294b;
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
/* Боковое меню */
|
/* Боковое меню */
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 250px;
|
width: 270px;
|
||||||
background-color: #333;
|
background-color: #3d74c7;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-right: 1px solid #444;
|
border-right: 1px solid white;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
/* Занимает всю высоту экрана */
|
/* Занимает всю высоту экрана */
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
@ -36,14 +36,15 @@ h2 {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: #444;
|
background-color: #3d74c7;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
border: 1px solid white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item-header:hover {
|
.menu-item-header:hover {
|
||||||
background-color: #222;
|
background-color: #195fc9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenu {
|
.submenu {
|
||||||
|
|
@ -57,8 +58,8 @@ h2 {
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: #444;
|
background-color: #3d74c7;
|
||||||
border: 1px solid #333;
|
border: 1px solid white;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -66,5 +67,5 @@ h2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab:hover {
|
.tab:hover {
|
||||||
background-color: #222;
|
background-color: #3d74c7;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
.tree-table {
|
||||||
|
max-width: 90vw; /* Ограничение ширины таблицы, чтобы не растягивалась */
|
||||||
|
min-width: 400px; /* Минимальная ширина для нормального отображения */
|
||||||
|
margin: 0 auto; /* Центрирование */
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-table-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 2px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-table-column {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 150px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-table-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-table-body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-table-items {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ограничение по ширине, чтобы элементы не растягивали таблицу */
|
||||||
|
.tree-table-item {
|
||||||
|
width: 170px;
|
||||||
|
/* Фиксированная ширина для всех элементов */
|
||||||
|
height: 40px;
|
||||||
|
/* Фиксированная высота */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-table-item:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
background: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/* src/Style/common.css */
|
||||||
|
/* Вкладки */
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
background-color: #3d74c7;
|
||||||
|
border-bottom: 2px solid #195fc9;
|
||||||
|
overflow-x: auto;
|
||||||
|
border-radius: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #3d74c7;
|
||||||
|
color: white;
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
cursor: pointer;
|
||||||
|
max-width: 250px;
|
||||||
|
min-width: 100px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab.active {
|
||||||
|
background-color: #195fc9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-tab {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue