mirror of
https://github.com/joaovitoriasilva/endurain.git
synced 2026-01-09 15:57:59 -05:00
Frontend revamp with Vue
[frontend] Activity view map, stats and graph completed, activity gear missing [frontend] Home page shows banner displaying activity upload status when uploading .gpx file [frontend] Home page updates week and month status on activity upload [frontend] Fixed minor UI issues
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<div align="center">
|
||||
<a title="Crowdin" target="_blank" href="https://crowdin.com/project/endurain"><img src="https://badges.crowdin.net/endurain/localized.svg"></a>
|
||||
<img src="frontend/img/logo/logo.png" width="128" height="128">
|
||||
|
||||
# Endurain
|
||||
|
||||
462
frontend_vue/package-lock.json
generated
462
frontend_vue/package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.6",
|
||||
"bootstrap": "^5.3.2",
|
||||
"chart.js": "^4.4.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"pinia": "^2.1.7",
|
||||
@@ -45,9 +46,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
|
||||
"integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz",
|
||||
"integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -471,9 +472,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz",
|
||||
"integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
|
||||
"version": "8.57.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
|
||||
"integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
@@ -579,12 +580,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@intlify/core-base": {
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.9.1.tgz",
|
||||
"integrity": "sha512-qsV15dg7jNX2faBRyKMgZS8UcFJViWEUPLdzZ9UR0kQZpFVeIpc0AG7ZOfeP7pX2T9SQ5jSiorq/tii9nkkafA==",
|
||||
"version": "9.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.10.1.tgz",
|
||||
"integrity": "sha512-0+Wtjj04GIyglh5KKiNjRwgjpHrhqqGZhaKY/QVjjogWKZq5WHROrTi84pNVsRN18QynyPmjtsVUWqFKPQ45xQ==",
|
||||
"dependencies": {
|
||||
"@intlify/message-compiler": "9.9.1",
|
||||
"@intlify/shared": "9.9.1"
|
||||
"@intlify/message-compiler": "9.10.1",
|
||||
"@intlify/shared": "9.10.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
@@ -594,11 +595,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/message-compiler": {
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.9.1.tgz",
|
||||
"integrity": "sha512-zTvP6X6HeumHOXuAE1CMMsV6tTX+opKMOxO1OHTCg5N5Sm/F7d8o2jdT6W6L5oHUsJ/vvkGefHIs7Q3hfowmsA==",
|
||||
"version": "9.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.10.1.tgz",
|
||||
"integrity": "sha512-b68UTmRhgZfswJZI7VAgW6BXZK5JOpoi5swMLGr4j6ss2XbFY13kiw+Hu+xYAfulMPSapcHzdWHnq21VGnMCnA==",
|
||||
"dependencies": {
|
||||
"@intlify/shared": "9.9.1",
|
||||
"@intlify/shared": "9.10.1",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -609,9 +610,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/shared": {
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.9.1.tgz",
|
||||
"integrity": "sha512-b3Pta1nwkz5rGq434v0psHwEwHGy1pYCttfcM22IE//K9owbpkEvFptx9VcuRAxjQdrO2If249cmDDjBu5wMDA==",
|
||||
"version": "9.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.10.1.tgz",
|
||||
"integrity": "sha512-liyH3UMoglHBUn70iCYcy9CQlInx/lp50W2aeSxqqrvmG+LDj/Jj7tBJhBoQL4fECkldGhbmW0g2ommHfL6Wmw==",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
@@ -680,6 +681,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"node_modules/@kurkle/color": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
|
||||
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -754,9 +760,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.10.0.tgz",
|
||||
"integrity": "sha512-/MeDQmcD96nVoRumKUljsYOLqfv1YFJps+0pTrb2Z9Nl/w5qNUysMaWQsrd1mvAlNT4yza1iVyIu4Q4AgF6V3A==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz",
|
||||
"integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -767,9 +773,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.10.0.tgz",
|
||||
"integrity": "sha512-lvu0jK97mZDJdpZKDnZI93I0Om8lSDaiPx3OiCk0RXn3E8CMPJNS/wxjAvSJJzhhZpfjXsjLWL8LnS6qET4VNQ==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz",
|
||||
"integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -780,9 +786,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.10.0.tgz",
|
||||
"integrity": "sha512-uFpayx8I8tyOvDkD7X6n0PriDRWxcqEjqgtlxnUA/G9oS93ur9aZ8c8BEpzFmsed1TH5WZNG5IONB8IiW90TQg==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz",
|
||||
"integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -793,9 +799,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.10.0.tgz",
|
||||
"integrity": "sha512-nIdCX03qFKoR/MwQegQBK+qZoSpO3LESurVAC6s6jazLA1Mpmgzo3Nj3H1vydXp/JM29bkCiuF7tDuToj4+U9Q==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz",
|
||||
"integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -806,9 +812,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.10.0.tgz",
|
||||
"integrity": "sha512-Fz7a+y5sYhYZMQFRkOyCs4PLhICAnxRX/GnWYReaAoruUzuRtcf+Qnw+T0CoAWbHCuz2gBUwmWnUgQ67fb3FYw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz",
|
||||
"integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -819,9 +825,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.10.0.tgz",
|
||||
"integrity": "sha512-yPtF9jIix88orwfTi0lJiqINnlWo6p93MtZEoaehZnmCzEmLL0eqjA3eGVeyQhMtxdV+Mlsgfwhh0+M/k1/V7Q==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz",
|
||||
"integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -832,9 +838,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.10.0.tgz",
|
||||
"integrity": "sha512-9GW9yA30ib+vfFiwjX+N7PnjTnCMiUffhWj4vkG4ukYv1kJ4T9gHNg8zw+ChsOccM27G9yXrEtMScf1LaCuoWQ==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz",
|
||||
"integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -845,9 +851,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.10.0.tgz",
|
||||
"integrity": "sha512-X1ES+V4bMq2ws5fF4zHornxebNxMXye0ZZjUrzOrf7UMx1d6wMQtfcchZ8SqUnQPPHdOyOLW6fTcUiFgHFadRA==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz",
|
||||
"integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -858,9 +864,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.10.0.tgz",
|
||||
"integrity": "sha512-w/5OpT2EnI/Xvypw4FIhV34jmNqU5PZjZue2l2Y3ty1Ootm3SqhI+AmfhlUYGBTd9JnpneZCDnt3uNOiOBkMyw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz",
|
||||
"integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -871,9 +877,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.10.0.tgz",
|
||||
"integrity": "sha512-q/meftEe3QlwQiGYxD9rWwB21DoKQ9Q8wA40of/of6yGHhZuGfZO0c3WYkN9dNlopHlNT3mf5BPsUSxoPuVQaw==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz",
|
||||
"integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -884,9 +890,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.10.0.tgz",
|
||||
"integrity": "sha512-NrR6667wlUfP0BHaEIKgYM/2va+Oj+RjZSASbBMnszM9k+1AmliRjHc3lJIiOehtSSjqYiO7R6KLNrWOX+YNSQ==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz",
|
||||
"integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -897,9 +903,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.10.0.tgz",
|
||||
"integrity": "sha512-FV0Tpt84LPYDduIDcXvEC7HKtyXxdvhdAOvOeWMWbQNulxViH2O07QXkT/FffX4FqEI02jEbCJbr+YcuKdyyMg==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz",
|
||||
"integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -910,9 +916,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.10.0.tgz",
|
||||
"integrity": "sha512-OZoJd+o5TaTSQeFFQ6WjFCiltiYVjIdsXxwu/XZ8qRpsvMQr4UsVrE5UyT9RIvsnuF47DqkJKhhVZ2Q9YW9IpQ==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz",
|
||||
"integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -975,13 +981,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.2.2.tgz",
|
||||
"integrity": "sha512-3jpcdPAD7LwHUUiT2pZTj2U82I2Tcgg2oVPvKxhn6mDI2On6tfvPQTjAI4628GUGDZrCm4Zna9iQHm5cEexOAg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.1.tgz",
|
||||
"integrity": "sha512-xofQFwIzfdmLLlHa6ag0dPV8YsnKOCP1KdAeVVh34vSjN2dcUiXYCD9htu/9eM7t8Xln4v03U9HLxLpPlsXdZw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vitest/spy": "1.2.2",
|
||||
"@vitest/utils": "1.2.2",
|
||||
"@vitest/spy": "1.3.1",
|
||||
"@vitest/utils": "1.3.1",
|
||||
"chai": "^4.3.10"
|
||||
},
|
||||
"funding": {
|
||||
@@ -989,12 +995,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.2.2.tgz",
|
||||
"integrity": "sha512-JctG7QZ4LSDXr5CsUweFgcpEvrcxOV1Gft7uHrvkQ+fsAVylmWQvnaAr/HDp3LAH1fztGMQZugIheTWjaGzYIg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.1.tgz",
|
||||
"integrity": "sha512-5FzF9c3jG/z5bgCnjr8j9LNq/9OxV2uEBAITOXfoe3rdZJTdO7jzThth7FXv/6b+kdY65tpRQB7WaKhNZwX+Kg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vitest/utils": "1.2.2",
|
||||
"@vitest/utils": "1.3.1",
|
||||
"p-limit": "^5.0.0",
|
||||
"pathe": "^1.1.1"
|
||||
},
|
||||
@@ -1030,9 +1036,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.2.2.tgz",
|
||||
"integrity": "sha512-SmGY4saEw1+bwE1th6S/cZmPxz/Q4JWsl7LvbQIky2tKE35US4gd0Mjzqfr84/4OD0tikGWaWdMja/nWL5NIPA==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.1.tgz",
|
||||
"integrity": "sha512-EF++BZbt6RZmOlE3SuTPu/NfwBF6q4ABS37HHXzs2LUVPBLx2QoY/K0fKpRChSo8eLiuxcbCVfqKgx/dplCDuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"magic-string": "^0.30.5",
|
||||
@@ -1044,9 +1050,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.2.2.tgz",
|
||||
"integrity": "sha512-k9Gcahssw8d7X3pSLq3e3XEu/0L78mUkCjivUqCQeXJm9clfXR/Td8+AP+VC1O6fKPIDLcHDTAmBOINVuv6+7g==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.1.tgz",
|
||||
"integrity": "sha512-xAcW+S099ylC9VLU7eZfdT9myV67Nor9w9zhf0mGCYJSO+zM2839tOeROTdikOi/8Qeusffvxb/MyBSOja1Uig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tinyspy": "^2.2.0"
|
||||
@@ -1056,9 +1062,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.2.2.tgz",
|
||||
"integrity": "sha512-WKITBHLsBHlpjnDQahr+XK6RE7MiAsgrIkr0pGhQ9ygoxBfUeG0lUG5iLlzqjmKSlBv3+j5EGsriBzh+C3Tq9g==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.1.tgz",
|
||||
"integrity": "sha512-d3Waie/299qqRyHTm2DjADeTaNdNSVsnwHPWrs20JMpjh6eiVq7ggggweO8rc4arhf6rRkWuHKwvxGvejUXZZQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"diff-sequences": "^29.6.3",
|
||||
@@ -1071,12 +1077,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.19.tgz",
|
||||
"integrity": "sha512-gj81785z0JNzRcU0Mq98E56e4ltO1yf8k5PQ+tV/7YHnbZkrM0fyFyuttnN8ngJZjbpofWE/m4qjKBiLl8Ju4w==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.21.tgz",
|
||||
"integrity": "sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.9",
|
||||
"@vue/shared": "3.4.19",
|
||||
"@vue/shared": "3.4.21",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
@@ -1088,27 +1094,27 @@
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.19.tgz",
|
||||
"integrity": "sha512-vm6+cogWrshjqEHTzIDCp72DKtea8Ry/QVpQRYoyTIg9k7QZDX6D8+HGURjtmatfgM8xgCFtJJaOlCaRYRK3QA==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.21.tgz",
|
||||
"integrity": "sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.4.19",
|
||||
"@vue/shared": "3.4.19"
|
||||
"@vue/compiler-core": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.19.tgz",
|
||||
"integrity": "sha512-LQ3U4SN0DlvV0xhr1lUsgLCYlwQfUfetyPxkKYu7dkfvx7g3ojrGAkw0AERLOKYXuAGnqFsEuytkdcComei3Yg==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.21.tgz",
|
||||
"integrity": "sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.9",
|
||||
"@vue/compiler-core": "3.4.19",
|
||||
"@vue/compiler-dom": "3.4.19",
|
||||
"@vue/compiler-ssr": "3.4.19",
|
||||
"@vue/shared": "3.4.19",
|
||||
"@vue/compiler-core": "3.4.21",
|
||||
"@vue/compiler-dom": "3.4.21",
|
||||
"@vue/compiler-ssr": "3.4.21",
|
||||
"@vue/shared": "3.4.21",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.6",
|
||||
"postcss": "^8.4.33",
|
||||
"magic-string": "^0.30.7",
|
||||
"postcss": "^8.4.35",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
@@ -1118,18 +1124,18 @@
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.19.tgz",
|
||||
"integrity": "sha512-P0PLKC4+u4OMJ8sinba/5Z/iDT84uMRRlrWzadgLA69opCpI1gG4N55qDSC+dedwq2fJtzmGald05LWR5TFfLw==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.21.tgz",
|
||||
"integrity": "sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.19",
|
||||
"@vue/shared": "3.4.19"
|
||||
"@vue/compiler-dom": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz",
|
||||
"integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA=="
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.1.tgz",
|
||||
"integrity": "sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA=="
|
||||
},
|
||||
"node_modules/@vue/eslint-config-prettier": {
|
||||
"version": "8.0.0",
|
||||
@@ -1146,48 +1152,48 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.19.tgz",
|
||||
"integrity": "sha512-+VcwrQvLZgEclGZRHx4O2XhyEEcKaBi50WbxdVItEezUf4fqRh838Ix6amWTdX0CNb/b6t3Gkz3eOebfcSt+UA==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.21.tgz",
|
||||
"integrity": "sha512-UhenImdc0L0/4ahGCyEzc/pZNwVgcglGy9HVzJ1Bq2Mm9qXOpP8RyNTjookw/gOCUlXSEtuZ2fUg5nrHcoqJcw==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.4.19"
|
||||
"@vue/shared": "3.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.19.tgz",
|
||||
"integrity": "sha512-/Z3tFwOrerJB/oyutmJGoYbuoadphDcJAd5jOuJE86THNZji9pYjZroQ2NFsZkTxOq0GJbb+s2kxTYToDiyZzw==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.21.tgz",
|
||||
"integrity": "sha512-pQthsuYzE1XcGZznTKn73G0s14eCJcjaLvp3/DKeYWoFacD9glJoqlNBxt3W2c5S40t6CCcpPf+jG01N3ULyrA==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.4.19",
|
||||
"@vue/shared": "3.4.19"
|
||||
"@vue/reactivity": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.19.tgz",
|
||||
"integrity": "sha512-IyZzIDqfNCF0OyZOauL+F4yzjMPN2rPd8nhqPP2N1lBn3kYqJpPHHru+83Rkvo2lHz5mW+rEeIMEF9qY3PB94g==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.21.tgz",
|
||||
"integrity": "sha512-gvf+C9cFpevsQxbkRBS1NpU8CqxKw0ebqMvLwcGQrNpx6gqRDodqKqA+A2VZZpQ9RpK2f9yfg8VbW/EpdFUOJw==",
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.4.19",
|
||||
"@vue/shared": "3.4.19",
|
||||
"@vue/runtime-core": "3.4.21",
|
||||
"@vue/shared": "3.4.21",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.19.tgz",
|
||||
"integrity": "sha512-eAj2p0c429RZyyhtMRnttjcSToch+kTWxFPHlzGMkR28ZbF1PDlTcmGmlDxccBuqNd9iOQ7xPRPAGgPVj+YpQw==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.21.tgz",
|
||||
"integrity": "sha512-aV1gXyKSN6Rz+6kZ6kr5+Ll14YzmIbeuWe7ryJl5muJ4uwSwY/aStXTixx76TwkZFJLm1aAlA/HSWEJ4EyiMkg==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.4.19",
|
||||
"@vue/shared": "3.4.19"
|
||||
"@vue/compiler-ssr": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.4.19"
|
||||
"vue": "3.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.19.tgz",
|
||||
"integrity": "sha512-/KliRRHMF6LoiThEy+4c1Z4KB/gbPrGjWwJR+crg2otgrf/egKzRaCPvJ51S5oetgsgXLfc4Rm5ZgrKHZrtMSw=="
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.21.tgz",
|
||||
"integrity": "sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g=="
|
||||
},
|
||||
"node_modules/@vue/test-utils": {
|
||||
"version": "2.4.4",
|
||||
@@ -1333,9 +1339,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz",
|
||||
"integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==",
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
|
||||
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -1412,6 +1418,17 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chart.js": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz",
|
||||
"integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==",
|
||||
"dependencies": {
|
||||
"@kurkle/color": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/check-error": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
|
||||
@@ -1727,16 +1744,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
|
||||
"integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
|
||||
"version": "8.57.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
|
||||
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.4",
|
||||
"@eslint/js": "8.56.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@eslint/js": "8.57.0",
|
||||
"@humanwhocodes/config-array": "^0.11.14",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
@@ -1824,16 +1841,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-vue": {
|
||||
"version": "9.21.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.21.1.tgz",
|
||||
"integrity": "sha512-XVtI7z39yOVBFJyi8Ljbn7kY9yHzznKXL02qQYn+ta63Iy4A9JFBw6o4OSB9hyD2++tVT+su9kQqetUyCCwhjw==",
|
||||
"version": "9.22.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.22.0.tgz",
|
||||
"integrity": "sha512-7wCXv5zuVnBtZE/74z4yZ0CM8AjH6bk4MQGm7hZjUC2DBppKU5ioeOk5LGSg/s9a1ZJnIsdPLJpXnu1Rc+cVHg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
"nth-check": "^2.1.1",
|
||||
"postcss-selector-parser": "^6.0.13",
|
||||
"semver": "^7.5.4",
|
||||
"postcss-selector-parser": "^6.0.15",
|
||||
"semver": "^7.6.0",
|
||||
"vue-eslint-parser": "^9.4.2",
|
||||
"xml-name-validator": "^4.0.0"
|
||||
},
|
||||
@@ -2039,9 +2056,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.2.9",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
|
||||
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
|
||||
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
@@ -2216,9 +2233,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/http-proxy-agent": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.1.tgz",
|
||||
"integrity": "sha512-My1KCEPs6A0hb4qCVzYp8iEvA8j8YqcvXLZZH8C9OFuTYpYjHE7N2dtG3mRl1HMD4+VGXpF3XcDVcxGBT7yDZQ==",
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.0",
|
||||
@@ -2229,9 +2246,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.3.tgz",
|
||||
"integrity": "sha512-kCnwztfX0KZJSLOBrcL0emLeFako55NWMovvyPP2AjsghNk9RB1yjSI+jVumPHYZsNXegNoqupSW9IY3afSH8w==",
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
|
||||
"integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"agent-base": "^7.0.2",
|
||||
@@ -2400,14 +2417,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/js-beautify": {
|
||||
"version": "1.14.11",
|
||||
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.11.tgz",
|
||||
"integrity": "sha512-rPogWqAfoYh1Ryqqh2agUpVfbxAhbjuN1SmU86dskQUKouRiggUTCO4+2ym9UPXllc2WAp0J+T5qxn7Um3lCdw==",
|
||||
"version": "1.15.1",
|
||||
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz",
|
||||
"integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"config-chain": "^1.1.13",
|
||||
"editorconfig": "^1.0.3",
|
||||
"editorconfig": "^1.0.4",
|
||||
"glob": "^10.3.3",
|
||||
"js-cookie": "^3.0.5",
|
||||
"nopt": "^7.2.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -2419,6 +2437,21 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz",
|
||||
"integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
@@ -2593,9 +2626,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
|
||||
"integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==",
|
||||
"version": "0.30.8",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
|
||||
"integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
@@ -2664,9 +2697,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mlly": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.5.0.tgz",
|
||||
"integrity": "sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==",
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.6.1.tgz",
|
||||
"integrity": "sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.11.3",
|
||||
@@ -2720,9 +2753,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/npm-run-path": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz",
|
||||
"integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
|
||||
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"path-key": "^4.0.0"
|
||||
@@ -3199,9 +3232,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.10.0.tgz",
|
||||
"integrity": "sha512-t2v9G2AKxcQ8yrG+WGxctBes1AomT0M4ND7jTFBCVPXQ/WFTvNSefIrNSmLKhIKBrvN8SG+CZslimJcT3W2u2g==",
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz",
|
||||
"integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.5"
|
||||
@@ -3214,19 +3247,19 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.10.0",
|
||||
"@rollup/rollup-android-arm64": "4.10.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.10.0",
|
||||
"@rollup/rollup-darwin-x64": "4.10.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.10.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.10.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.10.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.10.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.10.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.10.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.10.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.10.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.10.0",
|
||||
"@rollup/rollup-android-arm-eabi": "4.12.0",
|
||||
"@rollup/rollup-android-arm64": "4.12.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.12.0",
|
||||
"@rollup/rollup-darwin-x64": "4.12.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.12.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.12.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.12.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.12.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.12.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.12.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.12.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.12.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.12.0",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -3478,12 +3511,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/strip-literal": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz",
|
||||
"integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz",
|
||||
"integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"acorn": "^8.10.0"
|
||||
"js-tokens": "^8.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
@@ -3660,9 +3693,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.2.tgz",
|
||||
"integrity": "sha512-uwiFebQbTWRIGbCaTEBVAfKqgqKNKMJ2uPXsXeLIZxM8MVMjoS3j0cG8NrPxdDIadaWnPSjrkLWffLSC+uiP3Q==",
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz",
|
||||
"integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.19.3",
|
||||
@@ -3715,9 +3748,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite-node": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.2.2.tgz",
|
||||
"integrity": "sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.1.tgz",
|
||||
"integrity": "sha512-azbRrqRxlWTJEVbzInZCTchx0X69M/XPTCz4H+TLvlTcR/xH/3hkRqhOakT41fMJCMzXTu4UvegkZiEoJAWvng==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cac": "^6.7.14",
|
||||
@@ -3737,18 +3770,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.2.2.tgz",
|
||||
"integrity": "sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz",
|
||||
"integrity": "sha512-/1QJqXs8YbCrfv/GPQ05wAZf2eakUPLPa18vkJAKE7RXOKfVHqMZZ1WlTjiwl6Gcn65M5vpNUB6EFLnEdRdEXQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@vitest/expect": "1.2.2",
|
||||
"@vitest/runner": "1.2.2",
|
||||
"@vitest/snapshot": "1.2.2",
|
||||
"@vitest/spy": "1.2.2",
|
||||
"@vitest/utils": "1.2.2",
|
||||
"@vitest/expect": "1.3.1",
|
||||
"@vitest/runner": "1.3.1",
|
||||
"@vitest/snapshot": "1.3.1",
|
||||
"@vitest/spy": "1.3.1",
|
||||
"@vitest/utils": "1.3.1",
|
||||
"acorn-walk": "^8.3.2",
|
||||
"cac": "^6.7.14",
|
||||
"chai": "^4.3.10",
|
||||
"debug": "^4.3.4",
|
||||
"execa": "^8.0.1",
|
||||
@@ -3757,11 +3789,11 @@
|
||||
"pathe": "^1.1.1",
|
||||
"picocolors": "^1.0.0",
|
||||
"std-env": "^3.5.0",
|
||||
"strip-literal": "^1.3.0",
|
||||
"strip-literal": "^2.0.0",
|
||||
"tinybench": "^2.5.1",
|
||||
"tinypool": "^0.8.2",
|
||||
"vite": "^5.0.0",
|
||||
"vite-node": "1.2.2",
|
||||
"vite-node": "1.3.1",
|
||||
"why-is-node-running": "^2.2.2"
|
||||
},
|
||||
"bin": {
|
||||
@@ -3776,8 +3808,8 @@
|
||||
"peerDependencies": {
|
||||
"@edge-runtime/vm": "*",
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"@vitest/browser": "^1.0.0",
|
||||
"@vitest/ui": "^1.0.0",
|
||||
"@vitest/browser": "1.3.1",
|
||||
"@vitest/ui": "1.3.1",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*"
|
||||
},
|
||||
@@ -3803,15 +3835,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.4.19",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.19.tgz",
|
||||
"integrity": "sha512-W/7Fc9KUkajFU8dBeDluM4sRGc/aa4YJnOYck8dkjgZoXtVsn3OeTGni66FV1l3+nvPA7VBFYtPioaGKUmEADw==",
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz",
|
||||
"integrity": "sha512-5hjyV/jLEIKD/jYl4cavMcnzKwjMKohureP8ejn3hhEjwhWIhWeuzL2kJAjzl/WyVsgPY56Sy4Z40C3lVshxXA==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.19",
|
||||
"@vue/compiler-sfc": "3.4.19",
|
||||
"@vue/runtime-dom": "3.4.19",
|
||||
"@vue/server-renderer": "3.4.19",
|
||||
"@vue/shared": "3.4.19"
|
||||
"@vue/compiler-dom": "3.4.21",
|
||||
"@vue/compiler-sfc": "3.4.21",
|
||||
"@vue/runtime-dom": "3.4.21",
|
||||
"@vue/server-renderer": "3.4.21",
|
||||
"@vue/shared": "3.4.21"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
@@ -3853,12 +3885,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-i18n": {
|
||||
"version": "9.9.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.9.1.tgz",
|
||||
"integrity": "sha512-xyQ4VspLdNSPTKBFBPWa1tvtj+9HuockZwgFeD2OhxxXuC2CWeNvV4seu2o9+vbQOyQbhAM5Ez56oxUrrnTWdw==",
|
||||
"version": "9.10.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.10.1.tgz",
|
||||
"integrity": "sha512-37HVJQZ/pZaRXGzFmmMomM1u1k7kndv3xCBPYHKEVfv5W3UVK67U/TpBug71ILYLNmjHLHdvTUPRF81pFT5fFg==",
|
||||
"dependencies": {
|
||||
"@intlify/core-base": "9.9.1",
|
||||
"@intlify/shared": "9.9.1",
|
||||
"@intlify/core-base": "9.10.1",
|
||||
"@intlify/shared": "9.10.1",
|
||||
"@vue/devtools-api": "^6.5.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -3872,11 +3904,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vue-router": {
|
||||
"version": "4.2.5",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz",
|
||||
"integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.0.tgz",
|
||||
"integrity": "sha512-dqUcs8tUeG+ssgWhcPbjHvazML16Oga5w34uCUmsk7i0BcnskoLGwjpa15fqMr2Fa5JgVBrdL2MEgqz6XZ/6IQ==",
|
||||
"dependencies": {
|
||||
"@vue/devtools-api": "^6.5.0"
|
||||
"@vue/devtools-api": "^6.5.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/posva"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.6",
|
||||
"bootstrap": "^5.3.2",
|
||||
"chart.js": "^4.4.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"pinia": "^2.1.7",
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<div v-else>
|
||||
<div ref="activityMap" class="map" style="height: 300px;" v-if="source === 'home'"></div>
|
||||
<div ref="activityMap" class="map" style="height: 500px;" v-if="source === 'activity'"></div>
|
||||
<div ref="activityMap" class="map" style="height: 300px;" v-if="sourceProp === 'home'"></div>
|
||||
<div ref="activityMap" class="map" style="height: 500px;" v-if="sourceProp === 'activity'"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
const isLoading = ref(true);
|
||||
const activityStreamLatLng = ref(null);
|
||||
const activityMap = ref(null);
|
||||
const source = ref(props.source);
|
||||
const sourceProp = ref(props.source);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
@@ -95,7 +95,7 @@ export default {
|
||||
isLoading,
|
||||
activityStreamLatLng,
|
||||
activityMap,
|
||||
source,
|
||||
sourceProp,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<canvas ref="chartCanvas"></canvas>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, onUnmounted, computed, watch } from 'vue';
|
||||
import { Chart, registerables } from 'chart.js';
|
||||
Chart.register(...registerables);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
activity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
graphSelection: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
activityStreams: {
|
||||
type: Array,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const chartCanvas = ref(null);
|
||||
let myChart = null;
|
||||
const computedChartData = computed(() => {
|
||||
const data = [];
|
||||
let label = "";
|
||||
const labels = [];
|
||||
let roundValues = true;
|
||||
|
||||
props.activityStreams.forEach((stream) => {
|
||||
if (stream.stream_type == 1 && props.graphSelection == 'hr') {
|
||||
for (const streamPoint of stream.stream_waypoints) {
|
||||
data.push(parseInt(streamPoint.hr));
|
||||
label = "Heart Rate (bpm)";
|
||||
}
|
||||
} else if (stream.stream_type == 2 && props.graphSelection == 'power') {
|
||||
for (const streamPoint of stream.stream_waypoints) {
|
||||
data.push(parseInt(streamPoint.power));
|
||||
label = "Power (Watts)";
|
||||
}
|
||||
} else if (stream.stream_type == 3 && props.graphSelection == 'cad') {
|
||||
for (const streamPoint of stream.stream_waypoints) {
|
||||
data.push(parseInt(streamPoint.cad));
|
||||
label = "Cadence (rpm)";
|
||||
}
|
||||
} else if (stream.stream_type == 4 && props.graphSelection == 'ele') {
|
||||
for (const streamPoint of stream.stream_waypoints) {
|
||||
data.push(parseFloat(streamPoint.ele));
|
||||
label = "Elevation (m)";
|
||||
}
|
||||
} else if (stream.stream_type == 5 && props.graphSelection == 'vel') {
|
||||
data.push(...stream.stream_waypoints.map(velData => parseFloat((velData.vel * 3.6).toFixed(0))));
|
||||
label = "Velocity (km/h)";
|
||||
} else if (stream.stream_type == 6 && props.graphSelection == 'pace') {
|
||||
roundValues = false;
|
||||
stream.stream_waypoints.forEach(paceData => {
|
||||
if (paceData.pace == 0 || paceData.pace === null) {
|
||||
data.push(0);
|
||||
} else {
|
||||
if (props.activity.activity_type == 1 || props.activity.activity_type == 2 || props.activity.activity_type == 3) {
|
||||
data.push((paceData.pace * 1000) / 60);
|
||||
} else if (props.activity.activity_type == 8 || props.activity.activity_type == 9) {
|
||||
data.push((paceData.pace * 100) / 60);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (props.activity.activity_type == 1 || props.activity.activity_type == 2 || props.activity.activity_type == 3) {
|
||||
label = "Pace (min/km)";
|
||||
} else if (props.activity.activity_type == 8 || props.activity.activity_type == 9) {
|
||||
label = "Pace (min/100m)";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const dataDS = downsampleData(data, 200, roundValues);
|
||||
|
||||
const totalDistance = props.activity.distance / 1000;
|
||||
const numberOfDataPoints = dataDS.length;
|
||||
const distanceInterval = totalDistance / numberOfDataPoints;
|
||||
|
||||
for (let i = 0; i < numberOfDataPoints; i++) {
|
||||
labels.push((i * distanceInterval).toFixed(0) + "km");
|
||||
/* if (props.graphSelection == 'pace') {
|
||||
let paceCalculated = 0;
|
||||
if (props.activity.activity_type == 1 || props.activity.activity_type == 2 || props.activity.activity_type == 3) {
|
||||
paceCalculated = (dataDS[i] * 1000) / 60;
|
||||
} else if (props.activity.activity_type == 8 || props.activity.activity_type == 9) {
|
||||
paceCalculated = (dataDS[i] * 100) / 60;
|
||||
}
|
||||
const minutes = Math.floor(paceCalculated);
|
||||
const seconds = Math.round((paceCalculated - minutes) * 60);
|
||||
dataDS[i] = `${minutes}:${seconds.toString().padStart(2, '0')}`;
|
||||
} */
|
||||
}
|
||||
|
||||
return {
|
||||
datasets: [{
|
||||
label: label,
|
||||
data: dataDS,
|
||||
}],
|
||||
labels: labels,
|
||||
};
|
||||
});
|
||||
|
||||
watch(computedChartData, (newChartData) => {
|
||||
if (myChart.value) {
|
||||
myChart.value.data.datasets = newChartData.datasets;
|
||||
myChart.data.labels = newChartData.labels;
|
||||
myChart.value.update();
|
||||
}
|
||||
console.log(computedChartData.value)
|
||||
}, { deep: true });
|
||||
|
||||
function downsampleData(data, threshold, roundValues) {
|
||||
if (data.length <= threshold) {
|
||||
return data;
|
||||
}
|
||||
|
||||
const factor = Math.ceil(data.length / threshold);
|
||||
const downsampledData = [];
|
||||
|
||||
for (let i = 0; i < data.length; i += factor) {
|
||||
const chunk = data.slice(i, i + factor);
|
||||
const average = chunk.reduce((a, b) => a + b) / chunk.length;
|
||||
if (roundValues) {
|
||||
downsampledData.push(parseInt(average));
|
||||
}else{
|
||||
downsampledData.push(average);
|
||||
}
|
||||
}
|
||||
|
||||
return downsampledData;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
myChart = new Chart(chartCanvas.value.getContext('2d'), {
|
||||
type: 'line',
|
||||
data: computedChartData.value,
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: false
|
||||
},
|
||||
x: {
|
||||
autoSkip: true
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (myChart.value) {
|
||||
myChart.value.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
chartCanvas
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -11,10 +11,10 @@
|
||||
<img src="/src/assets/avatar/female1.png" alt="Default Female Avatar" width="55" height="55" class="rounded-circle" v-else>
|
||||
<div class="ms-3 me-3">
|
||||
<div class="fw-bold">
|
||||
<router-link :to="{ name: 'activity', params: { id: activity.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover" v-if="source === 'home'">
|
||||
<router-link :to="{ name: 'activity', params: { id: activity.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover" v-if="sourceProp === 'home'">
|
||||
{{ activity.name}}
|
||||
</router-link>
|
||||
<router-link :to="{ name: 'user', params: { id: userActivity.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover" v-if="source === 'activity'">
|
||||
<router-link :to="{ name: 'user', params: { id: userActivity.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover" v-if="sourceProp === 'activity'">
|
||||
{{ userActivity.name}}
|
||||
</router-link>
|
||||
</div>
|
||||
@@ -52,7 +52,7 @@
|
||||
<a class="btn btn-link btn-lg mt-1" :href="`https://www.strava.com/activities/${activity.strava_activity_id}`" role="button" v-if="activity.strava_activity_id">
|
||||
<font-awesome-icon :icon="['fab', 'fa-strava']" />
|
||||
</a>
|
||||
<div v-if="source === 'activity'">
|
||||
<div v-if="sourceProp === 'activity'">
|
||||
<button class="btn btn-link btn-lg" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<font-awesome-icon :icon="['fas', 'fa-ellipsis-vertical']" />
|
||||
</button>
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Activity title -->
|
||||
<h1 class="mt-3" v-if="source === 'activity'">
|
||||
<h1 class="mt-3" v-if="sourceProp === 'activity'">
|
||||
{{ activity.name }}
|
||||
</h1>
|
||||
<!-- Activity summary -->
|
||||
@@ -137,8 +137,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-flex mt-3" v-if="source === 'activity'">
|
||||
<!-- activity.activity_type == 1 || activity.activity_type == 2 || activity.activity_type == 3 -->
|
||||
<div class="row d-flex mt-3" v-if="sourceProp === 'activity'">
|
||||
<div class="col" v-if="activity.activity_type == 1 || activity.activity_type == 2 || activity.activity_type == 3">
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activitySummary.activityAvgPower") }}
|
||||
@@ -159,13 +158,12 @@
|
||||
<br>
|
||||
<span>{{ activity.elevation_loss }} m</span>
|
||||
</div>
|
||||
<!-- activity.activity_type != 9 || activity.activity_type != 1 -->
|
||||
<div class="col">
|
||||
<div class="col" v-if="activity.activity_type == 4 || activity.activity_type == 5 || activity.activity_type == 6">
|
||||
<span class="fw-lighter">{{ $t("activitySummary.activityAvgSpeed") }}</span>
|
||||
<br>
|
||||
<span>{{ (activity.average_speed * 3.6).toFixed(0) }} km/h</span>
|
||||
</div>
|
||||
<div class="col border-start border-opacity-50">
|
||||
<div class="col border-start border-opacity-50" v-if="activity.activity_type == 4 || activity.activity_type == 5 || activity.activity_type == 6">
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activitySummary.activityAvgPower") }}
|
||||
</span>
|
||||
@@ -173,7 +171,7 @@
|
||||
<span v-if="activity.average_power">{{ activity.average_power }} W</span>
|
||||
<span v-else>{{ $t("activitySummary.activityNoData") }}</span>
|
||||
</div>
|
||||
<div class="col border-start border-opacity-50">
|
||||
<div class="col border-start border-opacity-50" v-if="activity.activity_type == 4 || activity.activity_type == 5 || activity.activity_type == 6">
|
||||
<span class="fw-lighter">{{ $t("activitySummary.activityEleLoss") }}</span>
|
||||
<br>
|
||||
<span>{{ activity.elevation_loss }} m</span>
|
||||
@@ -183,7 +181,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, watchEffect, computed, nextTick } from 'vue';
|
||||
import { ref, onMounted, watchEffect, computed } from 'vue';
|
||||
import { users } from '@/services/user';
|
||||
import LoadingComponent from '@/components/LoadingComponent.vue';
|
||||
import { formatDate, formatTime, calculateTimeDifference } from '@/utils/dateTimeUtils';
|
||||
@@ -207,7 +205,7 @@ export default {
|
||||
const isLoading = ref(true);
|
||||
const userActivity = ref(null);
|
||||
const formattedPace = computed(() => formatPace(props.activity.pace));
|
||||
const source = ref(props.source);
|
||||
const sourceProp = ref(props.source);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
@@ -230,7 +228,7 @@ export default {
|
||||
formatTime,
|
||||
calculateTimeDifference,
|
||||
formattedPace,
|
||||
source,
|
||||
sourceProp,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"labelGear": "Gear",
|
||||
"labelGearNotSet": "Not set"
|
||||
"labelGearNotSet": "Not set",
|
||||
"modalLabelAddGear": "Add gear to activity",
|
||||
"modalLabelSelectGear": "Select gear",
|
||||
"modalButtonAddGear": "Add gear",
|
||||
"labelGraph": "Activity data graphs",
|
||||
"labelDownsampling": "Data downsampled to ~200 points"
|
||||
}
|
||||
@@ -6,5 +6,6 @@
|
||||
"radioFollowerActivities": "Followers activities",
|
||||
"successActivityAdded": "Activity added successfully",
|
||||
"errorActivityAdded": "Error adding activity",
|
||||
"errorActivityNotFound": "Activity not found"
|
||||
"errorActivityNotFound": "Activity not found",
|
||||
"processingActivity": "Processing activity"
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import { fetchGetRequest } from '@/utils/serviceUtils';
|
||||
|
||||
export const activityStreams = {
|
||||
async getActivitySteamsByActivityId(activityId) {
|
||||
return fetchGetRequest(`activities/streams/activity_id/${activityId}/all`);
|
||||
},
|
||||
async getActivitySteamByStreamTypeByActivityId(activityId, streamType) {
|
||||
return fetchGetRequest(`activities/streams/activity_id/${activityId}/stream_type/${streamType}`);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ export const gears = {
|
||||
getGearById(gearId) {
|
||||
return fetchGetRequest(`gear/id/${gearId}`);
|
||||
},
|
||||
getGearFromType(gearType) {
|
||||
return fetchGetRequest(`gear/type/${gearType}`);
|
||||
},
|
||||
getGearByNickname(nickname) {
|
||||
return fetchGetRequest(`gear/nickname/${nickname}`);
|
||||
},
|
||||
|
||||
@@ -14,6 +14,25 @@ export function formatPace(pace) {
|
||||
// Format the seconds
|
||||
const formattedSeconds = seconds < 10 ? `0${seconds}` : seconds;
|
||||
|
||||
// Return the formatted pace
|
||||
return `${minutes}:${formattedSeconds} min/km`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the pace for swimming activities.
|
||||
* @param {number} pace - The pace in minutes per 100 meters.
|
||||
* @returns {string} The formatted pace in the format "minutes:seconds min/km".
|
||||
*/
|
||||
export function formatPaceSwim(pace) {
|
||||
// Convert pace to seconds per 100 meters
|
||||
const pacePerKm = pace * 1000 / 60;
|
||||
// Calculate minutes and seconds
|
||||
const minutes = Math.floor(pacePerKm);
|
||||
const seconds = Math.round((pacePerKm - minutes) * 60);
|
||||
|
||||
// Format the seconds
|
||||
const formattedSeconds = seconds < 10 ? `0${seconds}` : seconds;
|
||||
|
||||
// Return the formatted pace
|
||||
return `${minutes}:${formattedSeconds} min/km`;
|
||||
}
|
||||
@@ -8,7 +8,7 @@ const API_URL = 'http://localhost:98/';
|
||||
* @returns {Promise<Object>} - A promise that resolves to the JSON response from the server.
|
||||
* @throws {Error} - If the response status is not ok.
|
||||
*/
|
||||
export async function fetchGetRequest(url, headers = {}) {
|
||||
export async function fetchGetRequest(url) {
|
||||
// Create the full URL by combining the API URL with the provided URL
|
||||
const fullUrl = `${API_URL}${url}`;
|
||||
// Send the GET request
|
||||
@@ -36,7 +36,7 @@ export async function fetchGetRequest(url, headers = {}) {
|
||||
* @returns {Promise<Object>} - A promise that resolves to the JSON response.
|
||||
* @throws {Error} - If the response status is not ok.
|
||||
*/
|
||||
export async function fetchGetRequestTokenAsParameter(url, token, headers = {}) {
|
||||
export async function fetchGetRequestTokenAsParameter(url, token) {
|
||||
// Check if a token is provided
|
||||
if (!token) {
|
||||
throw new Error('No token provided');
|
||||
@@ -67,7 +67,7 @@ export async function fetchGetRequestTokenAsParameter(url, token, headers = {})
|
||||
* @returns {Promise<Object>} - A promise that resolves to the JSON response from the server.
|
||||
* @throws {Error} - If the response status is not ok.
|
||||
*/
|
||||
export async function fetchPostFileRequest(url, formData, headers = {}) {
|
||||
export async function fetchPostFileRequest(url, formData) {
|
||||
// Create the full URL by combining the API URL with the provided URL
|
||||
const fullUrl = `${API_URL}${url}`;
|
||||
// Send the POST request
|
||||
@@ -94,7 +94,7 @@ export async function fetchPostFileRequest(url, formData, headers = {}) {
|
||||
* @returns {Promise<Object>} - A promise that resolves to the JSON response from the server.
|
||||
* @throws {Error} - If the response status is not ok.
|
||||
*/
|
||||
export async function fetchPostFormUrlEncoded(url, formData, headers = {}) {
|
||||
export async function fetchPostFormUrlEncoded(url, formData) {
|
||||
// Create the full URL by combining the API URL with the provided URL
|
||||
const fullUrl = `${API_URL}${url}`;
|
||||
// Send the POST request
|
||||
@@ -121,7 +121,7 @@ export async function fetchPostFormUrlEncoded(url, formData, headers = {}) {
|
||||
* @returns {Promise<Object>} - A promise that resolves to the JSON response.
|
||||
* @throws {Error} - If the response status is not ok.
|
||||
*/
|
||||
export async function fetchPostRequest(url, data, headers = {}) {
|
||||
export async function fetchPostRequest(url, data) {
|
||||
// Create the full URL by combining the API URL with the provided URL
|
||||
const fullUrl = `${API_URL}${url}`;
|
||||
// Send the POST request
|
||||
@@ -149,7 +149,7 @@ export async function fetchPostRequest(url, data, headers = {}) {
|
||||
* @returns {Promise<Object>} - A promise that resolves to the JSON response from the server.
|
||||
* @throws {Error} - If the response status is not ok.
|
||||
*/
|
||||
export async function fetchPutRequest(url, data, headers = {}) {
|
||||
export async function fetchPutRequest(url, data) {
|
||||
// Create the full URL by combining the API URL with the provided URL
|
||||
const fullUrl = `${API_URL}${url}`;
|
||||
// Send the PUT request
|
||||
@@ -176,7 +176,7 @@ export async function fetchPutRequest(url, data, headers = {}) {
|
||||
* @returns {Promise<Object>} - A promise that resolves to the JSON response from the server.
|
||||
* @throws {Error} - If the response status is not ok.
|
||||
*/
|
||||
export async function fetchDeleteRequest(url, headers = {}) {
|
||||
export async function fetchDeleteRequest(url) {
|
||||
// Create the full URL by combining the API URL with the provided URL
|
||||
const fullUrl = `${API_URL}${url}`;
|
||||
// Send the DELETE request
|
||||
|
||||
@@ -1,143 +1,252 @@
|
||||
<template>
|
||||
<LoadingComponent v-if="isLoading"/>
|
||||
<div v-else>
|
||||
<ActivitySummaryComponent v-if="activity" :activity="activity" :source="'activity'" />
|
||||
</div>
|
||||
|
||||
<!-- map zone -->
|
||||
<div class="mt-3 mb-3" v-if="isLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<div class="mt-3 mb-3" v-else>
|
||||
<ActivityMapComponent :activity="activity" :source="'activity'"/>
|
||||
</div>
|
||||
|
||||
<!-- gear zone -->
|
||||
<hr class="mb-2 mt-2">
|
||||
<div class="mt-3 mb-3" v-if="isLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center" v-else>
|
||||
<p class="pt-2">
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activity.labelGear") }}
|
||||
</span>
|
||||
<br>
|
||||
<span v-if="activity.activity_type == 1 || activity.activity_type == 2 || activity.activity_type == 3">
|
||||
<font-awesome-icon :icon="['fas', 'person-running']" />
|
||||
</span>
|
||||
<span v-else-if="activity.activity_type == 4 || activity.activity_type == 5 || activity.activity_type == 6 || activity.activity_type == 7">
|
||||
<font-awesome-icon :icon="['fas', 'fa-person-biking']" />
|
||||
</span>
|
||||
<span v-else-if="activity.activity_type == 8 || activity.activity_type == 9">
|
||||
<font-awesome-icon :icon="['fas', 'fa-person-swimming']" />
|
||||
</span>
|
||||
<span class="ms-2" v-if="activity.gear_id">{{ gear.nickname }}</span>
|
||||
<span class="ms-2" v-else>{{ $t("activity.labelGearNotSet") }}</span>
|
||||
</p>
|
||||
<div class="justify-content-end">
|
||||
<!-- add gear button -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearToActivityModal" v-if="!activity.gear_id">
|
||||
<font-awesome-icon :icon="['fas', 'fa-plus']" />
|
||||
</a>
|
||||
|
||||
|
||||
<!-- edit gear button -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#editGearActivityModal" v-if="activity.gear_id">
|
||||
<font-awesome-icon :icon="['far', 'fa-pen-to-square']" />
|
||||
</a>
|
||||
|
||||
<!-- Delete zone -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#deleteGearActivityModal" v-if="activity.gear_id">
|
||||
<font-awesome-icon :icon="['fas', 'fa-trash']" />
|
||||
</a>
|
||||
<template>
|
||||
<LoadingComponent v-if="isLoading"/>
|
||||
<div v-else>
|
||||
<ActivitySummaryComponent v-if="activity" :activity="activity" :source="'activity'" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- graphs -->
|
||||
<hr class="mb-2 mt-2">
|
||||
<!-- map zone -->
|
||||
<div class="mt-3 mb-3" v-if="isLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<div class="mt-3 mb-3" v-else>
|
||||
<ActivityMapComponent :activity="activity" :source="'activity'"/>
|
||||
</div>
|
||||
|
||||
<!-- gear zone -->
|
||||
<hr class="mb-2 mt-2">
|
||||
<div class="mt-3 mb-3" v-if="isLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center" v-else>
|
||||
<p class="pt-2">
|
||||
<span class="fw-lighter">
|
||||
{{ $t("activity.labelGear") }}
|
||||
</span>
|
||||
<br>
|
||||
<span v-if="activity.activity_type == 1 || activity.activity_type == 2 || activity.activity_type == 3">
|
||||
<font-awesome-icon :icon="['fas', 'person-running']" />
|
||||
</span>
|
||||
<span v-else-if="activity.activity_type == 4 || activity.activity_type == 5 || activity.activity_type == 6 || activity.activity_type == 7">
|
||||
<font-awesome-icon :icon="['fas', 'fa-person-biking']" />
|
||||
</span>
|
||||
<span v-else-if="activity.activity_type == 8 || activity.activity_type == 9">
|
||||
<font-awesome-icon :icon="['fas', 'fa-person-swimming']" />
|
||||
</span>
|
||||
<span class="ms-2" v-if="activity.gear_id">{{ gear.nickname }}</span>
|
||||
<span class="ms-2" v-else>{{ $t("activity.labelGearNotSet") }}</span>
|
||||
</p>
|
||||
<div class="justify-content-end">
|
||||
<!-- add gear button -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearToActivityModal" v-if="!activity.gear_id">
|
||||
<font-awesome-icon :icon="['fas', 'fa-plus']" />
|
||||
</a>
|
||||
|
||||
<div>
|
||||
<br>
|
||||
<button @click="goBack" type="button" class="w-100 btn btn-primary d-lg-none">{{ $t("generalItens.buttonBack") }}</button>
|
||||
</div>
|
||||
</template>
|
||||
<!-- modal -->
|
||||
<div class="modal fade" id="addGearToActivityModal" tabindex="-1" aria-labelledby="addGearToActivityModal" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="addGearToActivityModal">
|
||||
{{ $t("activity.modalLabelAddGear") }}
|
||||
</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
<form @submit.prevent="submitAddGearToActivityForm">
|
||||
<div class="modal-body">
|
||||
<!-- gear type fields -->
|
||||
<label for="gearIDAdd"><b>* {{ $t("activity.modalLabelSelectGear") }}</b></label>
|
||||
<select class="form-control" name="gearIDAdd" required>
|
||||
<option v-for="gear in gearsByType" :key="gear.id" :value="gear.id">
|
||||
{{ gear.nickname }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
{{ $t("generalItens.buttonClose") }}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-success" data-bs-dismiss="modal" name="addGearToActivity">
|
||||
{{ $t("activity.modalButtonAddGear") }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, onUnmounted, watchEffect, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
// Importing the stores
|
||||
import { useSuccessAlertStore } from '@/stores/Alerts/successAlert';
|
||||
import { useErrorAlertStore } from '@/stores/Alerts/errorAlert';
|
||||
// Importing the components
|
||||
import ActivitySummaryComponent from '@/components/Activities/ActivitySummaryComponent.vue';
|
||||
import ActivityMapComponent from '@/components/Activities/ActivityMapComponent.vue';
|
||||
import NoItemsFoundComponent from '@/components/NoItemsFoundComponents.vue';
|
||||
import ErrorAlertComponent from '@/components/Alerts/ErrorAlertComponent.vue';
|
||||
import SuccessAlertComponent from '@/components/Alerts/SuccessAlertComponent.vue';
|
||||
import LoadingComponent from '@/components/LoadingComponent.vue';
|
||||
// Importing the services
|
||||
import { gears } from '@/services/gears';
|
||||
import { activities } from '@/services/activities';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NoItemsFoundComponent,
|
||||
ActivitySummaryComponent,
|
||||
ActivityMapComponent,
|
||||
LoadingComponent,
|
||||
ErrorAlertComponent,
|
||||
SuccessAlertComponent,
|
||||
},
|
||||
setup (){
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const errorAlertStore = useErrorAlertStore();
|
||||
const successAlertStore = useSuccessAlertStore();
|
||||
const isLoading = ref(true);
|
||||
const errorMessage = ref('');
|
||||
const successMessage = ref('');
|
||||
const activity = ref(null);
|
||||
const gear = ref(null);
|
||||
<!-- edit gear button -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#editGearActivityModal" v-if="activity.gear_id">
|
||||
<font-awesome-icon :icon="['far', 'fa-pen-to-square']" />
|
||||
</a>
|
||||
|
||||
/**
|
||||
* Function to navigate back to the previous page.
|
||||
*/
|
||||
function goBack() {
|
||||
route.go(-1);
|
||||
}
|
||||
<!-- Delete zone -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#deleteGearActivityModal" v-if="activity.gear_id">
|
||||
<font-awesome-icon :icon="['fas', 'fa-trash']" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
onMounted(async () => {
|
||||
try{
|
||||
activity.value = await activities.getActivityById(route.params.id);
|
||||
if (!activity.value) {
|
||||
router.push({ path: '/', query: { activityFound: 'false' } });
|
||||
}
|
||||
if (activity.value.gear_id) {
|
||||
gear.value = await gears.getGearById(activity.value.gear_id);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.toString().includes('422')) {
|
||||
router.push({ path: '/', query: { activityFound: 'false' } });
|
||||
}
|
||||
// If there is an error, set the error message and show the error alert.
|
||||
errorMessage.value = t('generalItens.errorFetchingInfo') + " - " + error.toString();
|
||||
errorAlertStore.setAlertMessage(errorMessage.value);
|
||||
<!-- graphs -->
|
||||
<hr class="mb-2 mt-2">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<p>{{ $t("activity.labelGraph") }}</p>
|
||||
<ul class="nav nav-pills flex-column mb-auto" id="sidebarLineGraph">
|
||||
<li class="nav-item" v-for="item in graphItems" :key="item.type">
|
||||
<a href="javascript:void(0);" class="nav-link text-secondary"
|
||||
:class="{ 'active text-white': graphSelection === item.type }"
|
||||
@click="selectGraph(item.type)">
|
||||
{{ item.label }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="mt-2">{{ $t("activity.labelDownsampling") }}</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<LoadingComponent v-if="isLoading"/>
|
||||
<div v-else>
|
||||
<ActivityStreamsLineChartComponent :activity="activity" :graphSelection="graphSelection" :activityStreams="activityActivityStreams" v-if="graphSelection === 'hr'"/>
|
||||
<ActivityStreamsLineChartComponent :activity="activity" :graphSelection="graphSelection" :activityStreams="activityActivityStreams" v-if="graphSelection === 'power'"/>
|
||||
<ActivityStreamsLineChartComponent :activity="activity" :graphSelection="graphSelection" :activityStreams="activityActivityStreams" v-if="graphSelection === 'cad'"/>
|
||||
<ActivityStreamsLineChartComponent :activity="activity" :graphSelection="graphSelection" :activityStreams="activityActivityStreams" v-if="graphSelection === 'ele'"/>
|
||||
<ActivityStreamsLineChartComponent :activity="activity" :graphSelection="graphSelection" :activityStreams="activityActivityStreams" v-if="graphSelection === 'vel'"/>
|
||||
<ActivityStreamsLineChartComponent :activity="activity" :graphSelection="graphSelection" :activityStreams="activityActivityStreams" v-if="graphSelection === 'pace'"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<br>
|
||||
<button @click="goBack" type="button" class="w-100 btn btn-primary d-lg-none">{{ $t("generalItens.buttonBack") }}</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
// Importing the stores
|
||||
import { useSuccessAlertStore } from '@/stores/Alerts/successAlert';
|
||||
import { useErrorAlertStore } from '@/stores/Alerts/errorAlert';
|
||||
// Importing the components
|
||||
import ActivitySummaryComponent from '@/components/Activities/ActivitySummaryComponent.vue';
|
||||
import ActivityMapComponent from '@/components/Activities/ActivityMapComponent.vue';
|
||||
import ActivityStreamsLineChartComponent from '@/components/Activities/ActivityStreamsLineChartComponent.vue';
|
||||
import NoItemsFoundComponent from '@/components/NoItemsFoundComponents.vue';
|
||||
import ErrorAlertComponent from '@/components/Alerts/ErrorAlertComponent.vue';
|
||||
import SuccessAlertComponent from '@/components/Alerts/SuccessAlertComponent.vue';
|
||||
import LoadingComponent from '@/components/LoadingComponent.vue';
|
||||
// Importing the services
|
||||
import { gears } from '@/services/gears';
|
||||
import { activities } from '@/services/activities';
|
||||
import { activityStreams } from '@/services/activityStreams';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NoItemsFoundComponent,
|
||||
ActivitySummaryComponent,
|
||||
ActivityMapComponent,
|
||||
ActivityStreamsLineChartComponent,
|
||||
LoadingComponent,
|
||||
ErrorAlertComponent,
|
||||
SuccessAlertComponent,
|
||||
},
|
||||
setup (){
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const errorAlertStore = useErrorAlertStore();
|
||||
const successAlertStore = useSuccessAlertStore();
|
||||
const isLoading = ref(true);
|
||||
const errorMessage = ref('');
|
||||
const successMessage = ref('');
|
||||
const activity = ref(null);
|
||||
const gear = ref(null);
|
||||
const gearsByType = ref([]);
|
||||
const activityActivityStreams = ref([]);
|
||||
const graphSelection = ref('hr');
|
||||
const graphItems = ref([
|
||||
{ type: 'hr', label: 'HR' },
|
||||
{ type: 'power', label: 'Power' },
|
||||
{ type: 'ele', label: 'Elevation' },
|
||||
{ type: 'cad', label: 'Cadence' },
|
||||
{ type: 'pace', label: 'Pace' },
|
||||
]);
|
||||
|
||||
function selectGraph(type) {
|
||||
graphSelection.value = type;
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
});
|
||||
/**
|
||||
* Function to navigate back to the previous page.
|
||||
*/
|
||||
function goBack() {
|
||||
route.go(-1);
|
||||
}
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
activity,
|
||||
gear,
|
||||
errorMessage,
|
||||
successMessage,
|
||||
goBack,
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
function submitAddGearToActivityForm() {
|
||||
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
try{
|
||||
activity.value = await activities.getActivityById(route.params.id);
|
||||
if (!activity.value) {
|
||||
router.push({ path: '/', query: { activityFound: 'false' } });
|
||||
}
|
||||
if (activity.value.gear_id) {
|
||||
gear.value = await gears.getGearById(activity.value.gear_id);
|
||||
}
|
||||
|
||||
if (activity.value.activity_type == 1 || activity.value.activity_type == 2 || activity.value.activity_type == 3) {
|
||||
gearsByType.value = await gears.getGearFromType(2);
|
||||
} else {
|
||||
if (activity.value.activity_type == 4 || activity.value.activity_type == 5 || activity.value.activity_type == 6 || activity.value.activity_type == 7) {
|
||||
gearsByType.value = await gears.getGearFromType(1);
|
||||
graphItems.value = [
|
||||
{ type: 'hr', label: 'HR' },
|
||||
{ type: 'power', label: 'Power' },
|
||||
{ type: 'ele', label: 'Elevation' },
|
||||
{ type: 'cad', label: 'Cadence' },
|
||||
{ type: 'vel', label: 'Velocity' },
|
||||
]
|
||||
} else {
|
||||
if (activity.value.activity_type == 8 || activity.value.activity_type == 9) {
|
||||
gearsByType.value = await gears.getGearFromType(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activityActivityStreams.value = await activityStreams.getActivitySteamsByActivityId(route.params.id);
|
||||
|
||||
} catch (error) {
|
||||
if (error.toString().includes('422')) {
|
||||
router.push({ path: '/', query: { activityFound: 'false' } });
|
||||
}
|
||||
// If there is an error, set the error message and show the error alert.
|
||||
errorMessage.value = t('generalItens.errorFetchingInfo') + " - " + error.toString();
|
||||
errorAlertStore.setAlertMessage(errorMessage.value);
|
||||
}
|
||||
|
||||
isLoading.value = false;
|
||||
});
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
activity,
|
||||
gear,
|
||||
activityActivityStreams,
|
||||
errorMessage,
|
||||
successMessage,
|
||||
goBack,
|
||||
gearsByType,
|
||||
submitAddGearToActivityForm,
|
||||
graphSelection,
|
||||
graphItems,
|
||||
selectGraph
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -177,7 +177,7 @@
|
||||
|
||||
<script>
|
||||
// Importing the vue composition API
|
||||
import { ref, onMounted, onUnmounted, watchEffect, watch } from 'vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
// Importing the stores
|
||||
@@ -249,7 +249,7 @@ export default {
|
||||
successMessage.value = t('gear.successGearEdited');
|
||||
successAlertStore.setAlertMessage(successMessage.value);
|
||||
successAlertStore.setClosableState(true);
|
||||
} catch {
|
||||
} catch (error) {
|
||||
// If there is an error, set the error message and show the error alert.
|
||||
errorMessage.value = t('generalItens.errorEditingInfo') + " - " + error.toString();
|
||||
errorAlertStore.setAlertMessage(errorMessage.value);
|
||||
|
||||
@@ -63,6 +63,17 @@
|
||||
<!-- Success banners -->
|
||||
<SuccessAlertComponent v-if="successMessage"/>
|
||||
|
||||
<div v-if="isLoadingUploadActivity">
|
||||
<div class="alert alert-primary d-flex align-items-center" role="alert">
|
||||
<div class="spinner-border" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<div class="ms-1">
|
||||
<span>{{ $t("home.processingActivity") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- radio button -->
|
||||
<div class="btn-group mb-3 d-flex" role="group" aria-label="Activities radio toggle button group">
|
||||
<!-- user activities -->
|
||||
@@ -114,7 +125,7 @@
|
||||
<script>
|
||||
import { ref, onMounted, onUnmounted, watchEffect, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { activities } from '@/services/activities';
|
||||
// Importing the stores
|
||||
@@ -143,12 +154,12 @@ export default {
|
||||
},
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const successAlertStore = useSuccessAlertStore();
|
||||
const errorAlertStore = useErrorAlertStore();
|
||||
const selectedActivityView = ref('userActivities');
|
||||
const isLoading = ref(true);
|
||||
const isLoadingUploadActivity = ref(false);
|
||||
const activityFound = ref(true);
|
||||
const userMe = computed(() => userStore.userMe);
|
||||
const thisWeekDistances = computed(() => userStore.thisWeekDistances);
|
||||
@@ -194,6 +205,8 @@ export default {
|
||||
};
|
||||
|
||||
const submitUploadFileForm = async () => {
|
||||
// Set the loading state
|
||||
isLoadingUploadActivity.value = true;
|
||||
// Get the file input
|
||||
const fileInput = document.querySelector('input[type="file"]');
|
||||
|
||||
@@ -220,10 +233,17 @@ export default {
|
||||
if (modalInstance) {
|
||||
modalInstance.hide();
|
||||
} */
|
||||
}catch (error) {
|
||||
// Fetch the user stats
|
||||
await userStore.fetchUserStats();
|
||||
// Fetch the user activities and user activities number
|
||||
await userStore.fetchUserActivitiesNumber();
|
||||
} catch (error) {
|
||||
// Set the error message
|
||||
errorMessage.value = t('generalItens.errorFetchingInfo') + " - " + error.toString();
|
||||
errorAlertStore.setAlertMessage(errorMessage.value);
|
||||
} finally {
|
||||
// Set the loading state
|
||||
isLoadingUploadActivity.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -272,6 +292,7 @@ export default {
|
||||
return {
|
||||
selectedActivityView,
|
||||
isLoading,
|
||||
isLoadingUploadActivity,
|
||||
userMe,
|
||||
thisWeekDistances,
|
||||
thisMonthDistances,
|
||||
|
||||
Reference in New Issue
Block a user