50 files changed
+1019
-440
No files matched your search
Generated
+246
-153
@@ -45,7 +45,7 @@
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"prettier": "^3.3.3",
|
||||
"vite": "^5.4.19"
|
||||
"vite": "6.3.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-linux-arm64-musl": "4.41.0"
|
||||
@@ -492,9 +492,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
|
||||
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -504,13 +504,13 @@
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
|
||||
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -520,13 +520,13 @@
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
|
||||
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -536,13 +536,13 @@
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -552,13 +552,13 @@
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
|
||||
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -568,13 +568,13 @@
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -584,13 +584,13 @@
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
|
||||
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -600,13 +600,13 @@
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -616,13 +616,13 @@
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
|
||||
"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
|
||||
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -632,13 +632,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
|
||||
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -648,13 +648,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
|
||||
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -664,13 +664,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
|
||||
"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
|
||||
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -680,13 +680,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
|
||||
"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
|
||||
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
@@ -696,13 +696,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
|
||||
"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
|
||||
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -712,13 +712,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
|
||||
"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
|
||||
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -728,13 +728,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
|
||||
"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
|
||||
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -744,13 +744,13 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -760,13 +760,29 @@
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
|
||||
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -776,13 +792,29 @@
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
|
||||
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -792,13 +824,13 @@
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -808,13 +840,13 @@
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
|
||||
"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
|
||||
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -824,13 +856,13 @@
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
|
||||
"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
|
||||
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -840,13 +872,13 @@
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
|
||||
"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
|
||||
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -856,7 +888,7 @@
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
@@ -3040,9 +3072,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3172,23 +3204,6 @@
|
||||
],
|
||||
"license": "CC-BY-4.0"
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
@@ -3259,6 +3274,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig/node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -3820,41 +3844,43 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.21.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
|
||||
"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
|
||||
"version": "0.25.5",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
|
||||
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.21.5",
|
||||
"@esbuild/android-arm": "0.21.5",
|
||||
"@esbuild/android-arm64": "0.21.5",
|
||||
"@esbuild/android-x64": "0.21.5",
|
||||
"@esbuild/darwin-arm64": "0.21.5",
|
||||
"@esbuild/darwin-x64": "0.21.5",
|
||||
"@esbuild/freebsd-arm64": "0.21.5",
|
||||
"@esbuild/freebsd-x64": "0.21.5",
|
||||
"@esbuild/linux-arm": "0.21.5",
|
||||
"@esbuild/linux-arm64": "0.21.5",
|
||||
"@esbuild/linux-ia32": "0.21.5",
|
||||
"@esbuild/linux-loong64": "0.21.5",
|
||||
"@esbuild/linux-mips64el": "0.21.5",
|
||||
"@esbuild/linux-ppc64": "0.21.5",
|
||||
"@esbuild/linux-riscv64": "0.21.5",
|
||||
"@esbuild/linux-s390x": "0.21.5",
|
||||
"@esbuild/linux-x64": "0.21.5",
|
||||
"@esbuild/netbsd-x64": "0.21.5",
|
||||
"@esbuild/openbsd-x64": "0.21.5",
|
||||
"@esbuild/sunos-x64": "0.21.5",
|
||||
"@esbuild/win32-arm64": "0.21.5",
|
||||
"@esbuild/win32-ia32": "0.21.5",
|
||||
"@esbuild/win32-x64": "0.21.5"
|
||||
"@esbuild/aix-ppc64": "0.25.5",
|
||||
"@esbuild/android-arm": "0.25.5",
|
||||
"@esbuild/android-arm64": "0.25.5",
|
||||
"@esbuild/android-x64": "0.25.5",
|
||||
"@esbuild/darwin-arm64": "0.25.5",
|
||||
"@esbuild/darwin-x64": "0.25.5",
|
||||
"@esbuild/freebsd-arm64": "0.25.5",
|
||||
"@esbuild/freebsd-x64": "0.25.5",
|
||||
"@esbuild/linux-arm": "0.25.5",
|
||||
"@esbuild/linux-arm64": "0.25.5",
|
||||
"@esbuild/linux-ia32": "0.25.5",
|
||||
"@esbuild/linux-loong64": "0.25.5",
|
||||
"@esbuild/linux-mips64el": "0.25.5",
|
||||
"@esbuild/linux-ppc64": "0.25.5",
|
||||
"@esbuild/linux-riscv64": "0.25.5",
|
||||
"@esbuild/linux-s390x": "0.25.5",
|
||||
"@esbuild/linux-x64": "0.25.5",
|
||||
"@esbuild/netbsd-arm64": "0.25.5",
|
||||
"@esbuild/netbsd-x64": "0.25.5",
|
||||
"@esbuild/openbsd-arm64": "0.25.5",
|
||||
"@esbuild/openbsd-x64": "0.25.5",
|
||||
"@esbuild/sunos-x64": "0.25.5",
|
||||
"@esbuild/win32-arm64": "0.25.5",
|
||||
"@esbuild/win32-ia32": "0.25.5",
|
||||
"@esbuild/win32-x64": "0.25.5"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
@@ -4052,6 +4078,23 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/globals": {
|
||||
"version": "13.24.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
|
||||
@@ -4184,6 +4227,20 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.4.6",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
|
||||
"integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@@ -6713,6 +6770,22 @@
|
||||
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
|
||||
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
@@ -6923,20 +6996,23 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.19",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
|
||||
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
|
||||
"version": "6.3.5",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
|
||||
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
"postcss": "^8.4.43",
|
||||
"rollup": "^4.20.0"
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.13"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || >=20.0.0"
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
@@ -6945,19 +7021,25 @@
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || >=20.0.0",
|
||||
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
"terser": "^5.16.0",
|
||||
"tsx": "^4.8.1",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"jiti": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
@@ -6978,6 +7060,12 @@
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
},
|
||||
"tsx": {
|
||||
"optional": true
|
||||
},
|
||||
"yaml": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -7133,12 +7221,17 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
|
||||
"integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
"node": ">= 14.6"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"prettier": "^3.3.3",
|
||||
"vite": "^5.4.19"
|
||||
"vite": "6.3.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-linux-arm64-musl": "4.41.0"
|
||||
|
||||
@@ -2,16 +2,17 @@ import Box from "@mui/material/Box";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import BackgroundSVG from "../../../assets/Images/background.svg";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const AppLayout = ({ children }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const ui = useSelector((state) => state.ui);
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: "100vh",
|
||||
backgroundColor: theme.palette.primaryBackground.main,
|
||||
backgroundImage: `url("${BackgroundSVG}")`,
|
||||
backgroundImage: ui?.mode === "dark" ? `url("${BackgroundSVG}")` : "none",
|
||||
backgroundSize: "100% 100%",
|
||||
backgroundPosition: "center",
|
||||
backgroundRepeat: "no-repeat",
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
ListSubheader,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Stack,
|
||||
@@ -39,6 +38,7 @@ import Docs from "../../assets/icons/docs.svg?react";
|
||||
import StatusPages from "../../assets/icons/status-pages.svg?react";
|
||||
import Discussions from "../../assets/icons/discussions.svg?react";
|
||||
import Notifications from "../../assets/icons/notifications.svg?react";
|
||||
import Logs from "../../assets/icons/logs.svg?react";
|
||||
|
||||
import "./index.css";
|
||||
|
||||
@@ -64,6 +64,7 @@ const getMenu = (t) => [
|
||||
|
||||
{ name: t("menu.statusPages"), path: "status", icon: <StatusPages /> },
|
||||
{ name: t("menu.maintenance"), path: "maintenance", icon: <Maintenance /> },
|
||||
{ name: t("menu.logs"), path: "logs", icon: <Logs /> },
|
||||
|
||||
{
|
||||
name: t("menu.settings"),
|
||||
|
||||
@@ -4,7 +4,7 @@ import SkeletonLayout from "./skeleton";
|
||||
// Utils
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import PropTypes from "prop-types";
|
||||
const StatusBoxes = ({ shouldRender, flexWrap = "nowrap", children }) => {
|
||||
const StatusBoxes = ({ shouldRender = true, flexWrap = "nowrap", children }) => {
|
||||
const theme = useTheme();
|
||||
if (!shouldRender) {
|
||||
return (
|
||||
|
||||
@@ -5,7 +5,7 @@ import PropTypes from "prop-types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
const TextLink = ({ text, linkText, href }) => {
|
||||
const TextLink = ({ text, linkText, href, target = "_self" }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
@@ -18,6 +18,7 @@ const TextLink = ({ text, linkText, href }) => {
|
||||
color="accent"
|
||||
to={href}
|
||||
component={RouterLink}
|
||||
target={target}
|
||||
>
|
||||
{linkText}
|
||||
</Link>
|
||||
@@ -29,6 +30,7 @@ TextLink.propTypes = {
|
||||
text: PropTypes.string,
|
||||
linkText: PropTypes.string,
|
||||
href: PropTypes.string,
|
||||
target: PropTypes.string,
|
||||
};
|
||||
|
||||
export default TextLink;
|
||||
@@ -0,0 +1,35 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { networkService } from "../main";
|
||||
import { createToast } from "../Utils/toastUtils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const useFetchLogs = () => {
|
||||
const { t } = useTranslation();
|
||||
const [logs, setLogs] = useState(undefined);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchLogs = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await networkService.getLogs();
|
||||
setLogs(response.data.data);
|
||||
createToast({
|
||||
body: t("logsPage.toast.fetchLogsSuccess"),
|
||||
});
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
createToast({
|
||||
message: error.message,
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
fetchLogs();
|
||||
}, [t]);
|
||||
return [logs, isLoading, error];
|
||||
};
|
||||
|
||||
export { useFetchLogs };
|
||||
@@ -0,0 +1,97 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Box from "@mui/material/Box";
|
||||
import Select from "../../../Components/Inputs/Select";
|
||||
import Typography from "@mui/material/Typography";
|
||||
|
||||
import { useFetchLogs } from "../../../Hooks/logHooks";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const formatLog = (theme, log, idx) => {
|
||||
const levelColors = {
|
||||
info: theme.palette.success.main,
|
||||
warn: theme.palette.warning.main,
|
||||
error: theme.palette.error.main,
|
||||
debug: theme.palette.accent.main,
|
||||
};
|
||||
|
||||
const color = levelColors[log.level] || theme.palette.primary.contrastText;
|
||||
|
||||
return (
|
||||
<span key={idx}>
|
||||
<span>[{log.timestamp}]</span>{" "}
|
||||
<span style={{ color, fontWeight: "bold" }}>{log.level.toUpperCase()}</span>
|
||||
{": "}
|
||||
{`(${log.service})`}
|
||||
{`(${log.method})`}
|
||||
{": "}
|
||||
{log.message}
|
||||
<br />
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const Logs = () => {
|
||||
// Local state
|
||||
const [logLevel, setLogLevel] = useState("all");
|
||||
|
||||
// Hooks
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const [logs, isLoading, error] = useFetchLogs();
|
||||
// Setup
|
||||
const LOG_LEVELS = [
|
||||
{ _id: "all", name: t("logsPage.logLevelSelect.values.all") },
|
||||
{ _id: "info", name: t("logsPage.logLevelSelect.values.info") },
|
||||
{ _id: "warn", name: t("logsPage.logLevelSelect.values.warn") },
|
||||
{ _id: "error", name: t("logsPage.logLevelSelect.values.error") },
|
||||
{ _id: "debug", name: t("logsPage.logLevelSelect.values.debug") },
|
||||
];
|
||||
return (
|
||||
<Stack gap={theme.spacing(4)}>
|
||||
<Box>
|
||||
<Typography variant="body">{t("logsPage.description")}</Typography>
|
||||
</Box>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(4)}
|
||||
>
|
||||
<Typography>{t("logsPage.logLevelSelect.title")}</Typography>
|
||||
<Select
|
||||
items={LOG_LEVELS}
|
||||
value={logLevel}
|
||||
onChange={(e) => {
|
||||
setLogLevel(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
|
||||
<Box
|
||||
component="pre"
|
||||
sx={{
|
||||
fontFamily: "monospace",
|
||||
color: theme.palette.primary.contrastText,
|
||||
padding: 2,
|
||||
borderRadius: 1,
|
||||
overflowX: "auto",
|
||||
whiteSpace: "pre-wrap",
|
||||
wordWrap: "break-word",
|
||||
}}
|
||||
>
|
||||
<code>
|
||||
{logs
|
||||
?.filter((log) => {
|
||||
if (logLevel === "all") return true;
|
||||
return log.level === logLevel;
|
||||
})
|
||||
.reverse()
|
||||
.map((log, idx) => formatLog(theme, log, idx))}
|
||||
</code>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default Logs;
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import DataTable from "../../../../Components/Table";
|
||||
import DataTable from "../../../../../Components/Table";
|
||||
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { TypeToPathMap } from "../../../../Utils/monitorUtils";
|
||||
import { TypeToPathMap } from "../../../../../Utils/monitorUtils";
|
||||
import PropTypes from "prop-types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import DataTable from "../../../../Components/Table";
|
||||
import DataTable from "../../../../../Components/Table";
|
||||
import Typography from "@mui/material/Typography";
|
||||
// Utils
|
||||
import PropTypes from "prop-types";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { TypeToPathMap } from "../../../../Utils/monitorUtils";
|
||||
import { TypeToPathMap } from "../../../../../Utils/monitorUtils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { createHeaderFactory } from "../../../../Components/Table/TableUtils";
|
||||
import { createHeaderFactory } from "../../../../../Components/Table/TableUtils";
|
||||
|
||||
const JobTable = ({ jobs = [] }) => {
|
||||
const theme = useTheme();
|
||||
@@ -0,0 +1,43 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import StatBox from "../../../../../Components/StatBox";
|
||||
import StatusBoxes from "../../../../../Components/StatusBoxes";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
const camelToTitle = (str) => {
|
||||
return str
|
||||
.replace(/([A-Z])/g, " $1")
|
||||
.toLowerCase()
|
||||
.replace(/^./, (m) => m.toUpperCase());
|
||||
};
|
||||
|
||||
const Metrics = ({ metrics = {} }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
const data = Object.keys(metrics)
|
||||
.filter((key) => key !== "jobsWithFailures")
|
||||
.map((key) => {
|
||||
return { key, title: camelToTitle(key), value: metrics[key] };
|
||||
});
|
||||
|
||||
return (
|
||||
<Stack gap={theme.spacing(2)}>
|
||||
<Typography variant="h2">{t("queuePage.metricsTable.title")}</Typography>
|
||||
<StatusBoxes flexWrap="wrap">
|
||||
{data.map((metric) => {
|
||||
return (
|
||||
<StatBox
|
||||
key={metric.key}
|
||||
heading={metric.title}
|
||||
subHeading={metric.value}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</StatusBoxes>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
export default Metrics;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import DataTable from "../../../../Components/Table";
|
||||
import DataTable from "../../../../../Components/Table";
|
||||
|
||||
// Utils
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -1,15 +1,14 @@
|
||||
// Components
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Breadcrumbs from "../../Components/Breadcrumbs";
|
||||
import JobTable from "./components/JobTable";
|
||||
import MetricsTable from "./components/MetricsTable";
|
||||
import Metrics from "./components/Metrics";
|
||||
import FailedJobTable from "./components/FailedJobTable";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
// Utils
|
||||
import { useState } from "react";
|
||||
import { useFetchQueueData, useFlushQueue } from "../../Hooks/queueHooks";
|
||||
import { useFetchQueueData, useFlushQueue } from "../../../Hooks/queueHooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
@@ -23,15 +22,13 @@ const QueueDetails = () => {
|
||||
const [jobs, metrics, isLoading, error] = useFetchQueueData(trigger);
|
||||
const [flushQueue, isFlushing, flushError] = useFlushQueue();
|
||||
|
||||
const BREADCRUMBS = [{ name: t("queuePage.title"), path: "/queue" }];
|
||||
if (isLoading) return <div>Loading...</div>;
|
||||
if (error || flushError) return <div>Error: {error.message}</div>;
|
||||
|
||||
return (
|
||||
<Stack gap={theme.spacing(20)}>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<Metrics metrics={metrics} />
|
||||
<JobTable jobs={jobs} />
|
||||
<MetricsTable metrics={metrics} />
|
||||
<FailedJobTable metrics={metrics} />
|
||||
|
||||
<ButtonGroup
|
||||
@@ -0,0 +1,41 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Breadcrumbs from "../../Components/Breadcrumbs";
|
||||
import Tabs from "@mui/material/Tabs";
|
||||
import Tab from "@mui/material/Tab";
|
||||
import Queue from "./Queue";
|
||||
import LogsComponent from "./Logs";
|
||||
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useState } from "react";
|
||||
|
||||
const Logs = () => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
|
||||
// Local state
|
||||
const [value, setValue] = useState(0);
|
||||
|
||||
// Handlers
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
const BREADCRUMBS = [{ name: t("logsPage.title"), path: "/logs" }];
|
||||
return (
|
||||
<Stack gap={theme.spacing(20)}>
|
||||
<Breadcrumbs list={BREADCRUMBS} />
|
||||
<Tabs
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<Tab label={t("logsPage.tabs.logs")} />
|
||||
<Tab label={t("logsPage.tabs.queue")} />
|
||||
</Tabs>
|
||||
{value === 0 && <LogsComponent />}
|
||||
{value === 1 && <Queue />}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default Logs;
|
||||
@@ -11,6 +11,8 @@ import { formatDurationRounded } from "../../../Utils/timeUtils";
|
||||
import { StatusLabel } from "../../../Components/Label";
|
||||
import { setRowsPerPage } from "../../../Features/UI/uiSlice";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import dayjs from "dayjs";
|
||||
/**
|
||||
* Component for pagination actions (first, previous, next, last).
|
||||
@@ -36,7 +38,8 @@ const MaintenanceTable = ({
|
||||
}) => {
|
||||
const rowsPerPage = useSelector((state) => state?.ui?.maintenance?.rowsPerPage ?? 5);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
const handleChangePage = (event, newPage) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
@@ -180,6 +183,18 @@ const MaintenanceTable = ({
|
||||
return (
|
||||
<>
|
||||
<DataTable
|
||||
config={{
|
||||
rowSX: {
|
||||
cursor: "pointer",
|
||||
"&:hover td": {
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
transition: "background-color .3s ease",
|
||||
},
|
||||
},
|
||||
onRowClick: (row) => {
|
||||
navigate(`/maintenance/create/${row._id}`);
|
||||
},
|
||||
}}
|
||||
headers={headers}
|
||||
data={maintenanceWindows}
|
||||
/>
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import ConfigBox from "../../Components/ConfigBox";
|
||||
// Utils
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Link from "../../Components/Link";
|
||||
|
||||
const SettingsDev = ({ isAdmin, HEADER_SX }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!isAdmin) return null;
|
||||
|
||||
return (
|
||||
<ConfigBox>
|
||||
<Box>
|
||||
<Typography
|
||||
component="h1"
|
||||
variant="h2"
|
||||
>
|
||||
{t("settingsDev")}
|
||||
</Typography>
|
||||
<Typography sx={HEADER_SX}>{t("settingsDevDescription")}</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
<Link
|
||||
level="secondary"
|
||||
label={t("settingsDevViewJobQueueDetails")}
|
||||
url="/queue"
|
||||
external={false}
|
||||
/>
|
||||
</Box>
|
||||
</ConfigBox>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsDev;
|
||||
@@ -4,6 +4,8 @@ import ConfigBox from "../../Components/ConfigBox";
|
||||
import TextInput from "../../Components/Inputs/TextInput";
|
||||
import Button from "@mui/material/Button";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { Switch } from "@mui/material";
|
||||
import TextLink from "../../Components/TextLink";
|
||||
// Utils
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { PropTypes } from "prop-types";
|
||||
@@ -12,7 +14,6 @@ import { useTranslation } from "react-i18next";
|
||||
import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments";
|
||||
import { useSendTestEmail } from "../../Hooks/useSendTestEmail";
|
||||
import { createToast } from "../../Utils/toastUtils";
|
||||
import { Switch } from "@mui/material";
|
||||
|
||||
const SettingsEmail = ({
|
||||
isAdmin,
|
||||
@@ -239,6 +240,46 @@ const SettingsEmail = ({
|
||||
/>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
<TextLink
|
||||
text={t("settingsEmailTransportLinkDescription")}
|
||||
linkText={t("settingsEmailTransportLinkText")}
|
||||
href="https://nodemailer.com/smtp"
|
||||
target="_blank"
|
||||
/>
|
||||
<Box
|
||||
component={"pre"}
|
||||
sx={{
|
||||
fontFamily: "monospace",
|
||||
p: 2,
|
||||
borderRadius: 1,
|
||||
overflow: "auto",
|
||||
}}
|
||||
>
|
||||
<code>
|
||||
{JSON.stringify(
|
||||
{
|
||||
host: systemEmailHost,
|
||||
port: systemEmailPort,
|
||||
secure: systemEmailSecure,
|
||||
auth: {
|
||||
user: systemEmailUser || systemEmailAddress,
|
||||
pass: "<your_password>",
|
||||
},
|
||||
name: systemEmailConnectionHost || "localhost",
|
||||
pool: systemEmailPool,
|
||||
tls: {
|
||||
rejectUnauthorized: systemEmailRejectUnauthorized,
|
||||
ignoreTLS: systemEmailIgnoreTLS,
|
||||
requireTLS: systemEmailRequireTLS,
|
||||
servername: systemEmailTLSServername,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</code>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
|
||||
@@ -8,7 +8,6 @@ import SettingsPagespeed from "./SettingsPagespeed";
|
||||
import SettingsDemoMonitors from "./SettingsDemoMonitors";
|
||||
import SettingsAbout from "./SettingsAbout";
|
||||
import SettingsEmail from "./SettingsEmail";
|
||||
import SettingsDev from "./SettingsDev";
|
||||
import Button from "@mui/material/Button";
|
||||
// Utils
|
||||
import { settingsValidation } from "../../Validation/validation";
|
||||
@@ -209,10 +208,7 @@ const Settings = () => {
|
||||
emailPasswordHasBeenReset={emailPasswordHasBeenReset}
|
||||
setEmailPasswordHasBeenReset={setEmailPasswordHasBeenReset}
|
||||
/>
|
||||
<SettingsDev
|
||||
isAdmin={isAdmin}
|
||||
HEADER_SX={HEADING_SX}
|
||||
/>
|
||||
|
||||
<SettingsAbout />
|
||||
<Stack
|
||||
direction="row"
|
||||
|
||||
@@ -90,6 +90,13 @@ const Content = ({
|
||||
isChecked={form.showUptimePercentage}
|
||||
onChange={handleFormChange}
|
||||
/>
|
||||
<Checkbox
|
||||
id="showAdminLoginLink"
|
||||
name="showAdminLoginLink"
|
||||
label={t("showAdminLoginLink")}
|
||||
isChecked={form.showAdminLoginLink}
|
||||
onChange={handleFormChange}
|
||||
/>
|
||||
</Stack>
|
||||
</ConfigStack>
|
||||
</Stack>
|
||||
|
||||
@@ -20,7 +20,7 @@ const TAB_LIST = ["General settings", "Contents"];
|
||||
|
||||
const ERROR_TAB_MAPPING = [
|
||||
["companyName", "url", "timezone", "color", "isPublished", "logo"],
|
||||
["monitors", "showUptimePercentage", "showCharts"],
|
||||
["monitors", "showUptimePercentage", "showCharts", "showAdminLoginLink"],
|
||||
];
|
||||
|
||||
const CreateStatusPage = () => {
|
||||
@@ -39,6 +39,7 @@ const CreateStatusPage = () => {
|
||||
monitors: [],
|
||||
showCharts: true,
|
||||
showUptimePercentage: true,
|
||||
showAdminLoginLink: false,
|
||||
});
|
||||
const [errors, setErrors] = useState({});
|
||||
const [selectedMonitors, setSelectedMonitors] = useState([]);
|
||||
@@ -195,6 +196,7 @@ const CreateStatusPage = () => {
|
||||
logo: newLogo,
|
||||
showCharts: statusPage?.showCharts ?? true,
|
||||
showUptimePercentage: statusPage?.showUptimePercentage ?? true,
|
||||
showAdminLoginLink: statusPage?.showAdminLoginLink ?? false,
|
||||
};
|
||||
});
|
||||
setSelectedMonitors(statusPageMonitors);
|
||||
|
||||
@@ -48,7 +48,7 @@ const PublicStatus = () => {
|
||||
let link = undefined;
|
||||
const isPublic = location.pathname.startsWith("/status/uptime/public");
|
||||
// Public status page
|
||||
if (isPublic) {
|
||||
if (isPublic && statusPage && statusPage.showAdminLoginLink === true) {
|
||||
sx = {
|
||||
paddingTop: theme.spacing(20),
|
||||
paddingLeft: "20vw",
|
||||
|
||||
@@ -51,7 +51,7 @@ import ProtectedRoute from "../Components/ProtectedRoute";
|
||||
import CreateNewMaintenanceWindow from "../Pages/Maintenance/CreateMaintenance";
|
||||
import withAdminCheck from "../Components/HOC/withAdminCheck";
|
||||
import BulkImport from "../Pages/Uptime/BulkImport";
|
||||
import Queue from "../Pages/Queue";
|
||||
import Logs from "../Pages/Logs";
|
||||
|
||||
const Routes = () => {
|
||||
const AdminCheckedRegister = withAdminCheck(AuthRegister);
|
||||
@@ -187,9 +187,10 @@ const Routes = () => {
|
||||
path="account/team"
|
||||
element={<Account open={"team"} />}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="queue"
|
||||
element={<Queue />}
|
||||
path="logs"
|
||||
element={<Logs />}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
|
||||
@@ -871,6 +871,9 @@ class NetworkService {
|
||||
if (form.showUptimePercentage !== undefined) {
|
||||
fd.append("showUptimePercentage", String(form.showUptimePercentage));
|
||||
}
|
||||
if (form.showAdminLoginLink !== undefined) {
|
||||
fd.append("showAdminLoginLink", String(form.showAdminLoginLink));
|
||||
}
|
||||
form.monitors &&
|
||||
form.monitors.forEach((monitorId) => {
|
||||
fd.append("monitors[]", monitorId);
|
||||
@@ -1041,6 +1044,14 @@ class NetworkService {
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
async getLogs() {
|
||||
return this.axiosInstance.get(`/logs`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default NetworkService;
|
||||
|
||||
@@ -407,6 +407,7 @@ const baseTheme = (palette) => ({
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
@@ -475,6 +476,8 @@ const baseTheme = (palette) => ({
|
||||
MuiTabs: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
height: "34px",
|
||||
minHeight: "34px",
|
||||
display: "inline-flex",
|
||||
borderRadius: 0,
|
||||
"& .MuiTabs-indicator": {
|
||||
|
||||
@@ -277,6 +277,7 @@ const statusPageValidation = joi.object({
|
||||
logo: logoImageValidation,
|
||||
showUptimePercentage: joi.boolean(),
|
||||
showCharts: joi.boolean(),
|
||||
showAdminLoginLink: joi.boolean(),
|
||||
});
|
||||
|
||||
const settingsValidation = joi.object({
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M21 5C21 6.65685 16.9706 8 12 8C7.02944 8 3 6.65685 3 5M21 5C21 3.34315 16.9706 2 12 2C7.02944 2 3 3.34315 3 5M21 5V19C21 20.66 17 22 12 22C7 22 3 20.66 3 19V5M21 12C21 13.66 17 15 12 15C7 15 3 13.66 3 12"
|
||||
stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 421 B |
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": "Nastala chyba při ověřování dat."
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
+54
-32
@@ -30,9 +30,6 @@
|
||||
"settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?",
|
||||
"settingsRemoveAllMonitorsDialogConfirm": "Yes, remove all monitors",
|
||||
"settingsAbout": "About",
|
||||
"settingsDev": "Developer",
|
||||
"settingsDevDescription": "Developer settings",
|
||||
"settingsDevViewJobQueueDetails": "View job queue details",
|
||||
"settingsDevelopedBy": "Developed by Bluewave Labs.",
|
||||
"settingsSave": "Save",
|
||||
"settingsSuccessSaved": "Settings saved successfully",
|
||||
@@ -319,6 +316,7 @@
|
||||
"statusPageCreateTabsContentFeaturesDescription": "Show more details on the status page",
|
||||
"showCharts": "Show charts",
|
||||
"showUptimePercentage": "Show uptime percentage",
|
||||
"showAdminLoginLink": "Show \"Administrator? Login Here\" link on the status page",
|
||||
"removeLogo": "Remove Logo",
|
||||
"statusPageStatus": "A public status page is not set up.",
|
||||
"statusPageStatusContactAdmin": "Please contact to your administrator",
|
||||
@@ -431,6 +429,7 @@
|
||||
"statusPages": "Status pages",
|
||||
"maintenance": "Maintenance",
|
||||
"integrations": "Integrations",
|
||||
"logs": "Logs",
|
||||
"settings": "Settings",
|
||||
"support": "Support",
|
||||
"discussions": "Discussions",
|
||||
@@ -450,6 +449,8 @@
|
||||
"settingsEmailPassword": "Email password - Password for authentication",
|
||||
"settingsEmailUser": "Email user - Username for authentication, overrides email address if specified",
|
||||
"settingsEmailFieldResetLabel": "Password is set. Click Reset to change it.",
|
||||
"settingsEmailTransportLinkDescription": "This builds an SMTP transport for NodeMailer",
|
||||
"settingsEmailTransportLinkText": "See specifications here",
|
||||
"state": "State",
|
||||
"statusBreadCrumbsStatusPages": "Status Pages",
|
||||
"statusBreadCrumbsDetails": "Details",
|
||||
@@ -510,13 +511,6 @@
|
||||
},
|
||||
"auth": {
|
||||
"common": {
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": "The password you provided does not match our records"
|
||||
}
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"continue": "Continue",
|
||||
"back": "Back"
|
||||
@@ -597,6 +591,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": "Error validating data."
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": "The password you provided does not match our records"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -717,23 +718,23 @@
|
||||
"webhookLabel": "Slack webhook URL",
|
||||
"webhookPlaceholder": "https://hooks.slack.com/services/..."
|
||||
},
|
||||
"pagerDutySettings": {
|
||||
"pagerdutySettings": {
|
||||
"title": "PagerDuty",
|
||||
"description": "Configure your PagerDuty integration here",
|
||||
"integrationKeyLabel": "Integration key",
|
||||
"integrationKeyPlaceholder": "1234567890"
|
||||
},
|
||||
"webhookSettings": {
|
||||
"title": "Webhook",
|
||||
"description": "Configure your webhook here",
|
||||
"webhookLabel": "Webhook URL",
|
||||
"webhookPlaceholder": "https://your-server.com/webhook"
|
||||
},
|
||||
"discordSettings": {
|
||||
"title": "Discord",
|
||||
"description": "Configure your Discord webhook here",
|
||||
"webhookLabel": "Discord Webhook URL",
|
||||
"webhookPlaceholder": "https://your-server.com/webhook"
|
||||
},
|
||||
"webhookSettings": {
|
||||
"title": "Webhook",
|
||||
"description": "Configure your webhook here",
|
||||
"webhookLabel": "Webhook URL",
|
||||
"webhookPlaceholder": "https://your-server.com/webhook"
|
||||
}
|
||||
},
|
||||
"notificationConfig": {
|
||||
@@ -749,13 +750,34 @@
|
||||
},
|
||||
"advancedMatching": "Advanced matching",
|
||||
"settingsEmailTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP",
|
||||
"settingsEmailIgnoreTLS": "Disable STARTTLS: Don't use TLS even if the server supports it",
|
||||
"settingsEmailRequireTLS": "Force STARTTLS: Require TLS upgrade, fail if not supported",
|
||||
"settingsEmailRejectUnauthorized": "Reject invalid certificates: Reject connections with self-signed or untrusted certificates",
|
||||
"settingsEmailSecure": "Use SSL (recommended): Encrypt the connection using SSL/TLS",
|
||||
"settingsEmailPool": "Enable connection pooling: Reuse existing connections to improve performance",
|
||||
"settingsEmailIgnoreTLS": "Ignore TLS - Disable STARTTLS",
|
||||
"settingsEmailRequireTLS": "Require TLS - Force STARTTLS",
|
||||
"settingsEmailRejectUnauthorized": "Reject Unauthorized",
|
||||
"settingsEmailSecure": "Secure - Use SSL",
|
||||
"settingsEmailPool": "Pool - Enable connection pooling",
|
||||
"sendTestNotifications": "Send test notifications",
|
||||
"selectAll": "Select all",
|
||||
"logsPage": {
|
||||
"title": "Logs",
|
||||
"description": "This page shows the latest 1000 lines of logs from the Checkmate server",
|
||||
"tabs": {
|
||||
"queue": "Job queue",
|
||||
"logs": "Server logs"
|
||||
},
|
||||
"toast": {
|
||||
"fetchLogsSuccess": "Logs fetched successfully"
|
||||
},
|
||||
"logLevelSelect": {
|
||||
"title": "Log level",
|
||||
"values": {
|
||||
"all": "All",
|
||||
"info": "Info",
|
||||
"warn": "Warn",
|
||||
"error": "Error",
|
||||
"debug": "Debug"
|
||||
}
|
||||
}
|
||||
},
|
||||
"queuePage": {
|
||||
"title": "Queue",
|
||||
"refreshButton": "Refresh",
|
||||
@@ -785,16 +807,16 @@
|
||||
"failCountHeader": "Fail count",
|
||||
"failedAtHeader": "Last failed at",
|
||||
"failReasonHeader": "Fail reason"
|
||||
},
|
||||
"export": {
|
||||
"title": "Export Monitors",
|
||||
"success": "Monitors exported successfully!",
|
||||
"failed": "Failed to export monitors"
|
||||
},
|
||||
"monitorActions": {
|
||||
"title": "Export/Import",
|
||||
"import": "Import Monitors",
|
||||
"export": "Export Monitors"
|
||||
}
|
||||
},
|
||||
"export": {
|
||||
"title": "Export Monitors",
|
||||
"success": "Monitors exported successfully!",
|
||||
"failed": "Failed to export monitors"
|
||||
},
|
||||
"monitorActions": {
|
||||
"title": "Export/Import",
|
||||
"import": "Import Monitors",
|
||||
"export": "Export Monitors"
|
||||
}
|
||||
}
|
||||
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
@@ -312,6 +312,7 @@
|
||||
"statusPageCreateTabsContentFeaturesDescription": "Mostrar mais detalhes na página de status",
|
||||
"showCharts": "Mostrar gráficos",
|
||||
"showUptimePercentage": "Mostrar porcentagem de Uptime",
|
||||
"showAdminLoginLink": "Mostrar o link \"Administrador? Efetue login aqui\" na página de status",
|
||||
"removeLogo": "Remover logo",
|
||||
"statusPageStatus": "Uma página de status pública não está configurada.",
|
||||
"statusPageStatusContactAdmin": "Entre em contato com seu administrador",
|
||||
@@ -583,6 +584,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +717,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +748,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
+131
-123
@@ -117,11 +117,11 @@
|
||||
"title": "",
|
||||
"checks": [""]
|
||||
},
|
||||
"createButton": "",
|
||||
"createTitle": "",
|
||||
"createButton": "Bildirim kanalı oluştur",
|
||||
"createTitle": "Bildirim kanalı",
|
||||
"create": {
|
||||
"success": "",
|
||||
"failed": ""
|
||||
"failed": "Bildirim kanalı oluşturulamadı"
|
||||
},
|
||||
"fetch": {
|
||||
"success": "",
|
||||
@@ -136,7 +136,7 @@
|
||||
"failed": ""
|
||||
},
|
||||
"test": {
|
||||
"success": "",
|
||||
"success": "Test bildirimi başarıyla gönderildi",
|
||||
"failed": ""
|
||||
}
|
||||
},
|
||||
@@ -373,33 +373,33 @@
|
||||
"pageSpeedApiKeyFieldDescription": "Sayfa hızı izlemeyi etkinleştirmek için Google PageSpeed API anahtarınızı girin. Anahtarı güncellemek için Sıfırla'ya tıklayın.",
|
||||
"pageSpeedApiKeyFieldResetLabel": "API anahtarı ayarlandı. Değiştirmek için Sıfırla'ya tıklayın.",
|
||||
"reset": "Sıfırla",
|
||||
"ignoreTLSError": "",
|
||||
"tlsErrorIgnored": "",
|
||||
"ignoreTLSError": "TLS/SSL hatalarını gözardı et",
|
||||
"tlsErrorIgnored": "TLS/SSL hataları gözardı ediliyor",
|
||||
"ignoreTLSErrorDescription": "",
|
||||
"createNew": "",
|
||||
"createNew": "Yeni oluştur",
|
||||
"greeting": {
|
||||
"prepend": "",
|
||||
"prepend": "Merhaba",
|
||||
"append": "",
|
||||
"overview": ""
|
||||
},
|
||||
"roles": {
|
||||
"superAdmin": "",
|
||||
"admin": "",
|
||||
"teamMember": "",
|
||||
"demoUser": ""
|
||||
"superAdmin": "Süper yönetici",
|
||||
"admin": "Yönetici",
|
||||
"teamMember": "Ekip elemanı",
|
||||
"demoUser": "Demo kullanıcısı"
|
||||
},
|
||||
"teamPanel": {
|
||||
"teamMembers": "",
|
||||
"teamMembers": "Ekip elemanları",
|
||||
"filter": {
|
||||
"all": "",
|
||||
"member": ""
|
||||
"all": "Tümü",
|
||||
"member": "Eleman"
|
||||
},
|
||||
"inviteTeamMember": "",
|
||||
"inviteNewTeamMember": "",
|
||||
"inviteTeamMember": "Ekip elemanı davet et",
|
||||
"inviteNewTeamMember": "Yeni ekip elemanı davet et",
|
||||
"inviteDescription": "",
|
||||
"email": "",
|
||||
"selectRole": "",
|
||||
"inviteLink": "",
|
||||
"email": "Eposta",
|
||||
"selectRole": "Rolü seçin",
|
||||
"inviteLink": "Davet linki",
|
||||
"cancel": "",
|
||||
"noMembers": "",
|
||||
"getToken": "",
|
||||
@@ -422,21 +422,21 @@
|
||||
"infrastructure": "",
|
||||
"incidents": "",
|
||||
"statusPages": "",
|
||||
"maintenance": "",
|
||||
"integrations": "",
|
||||
"settings": "",
|
||||
"support": "",
|
||||
"discussions": "",
|
||||
"docs": "",
|
||||
"changelog": "",
|
||||
"profile": "",
|
||||
"password": "",
|
||||
"team": "",
|
||||
"maintenance": "Bakım",
|
||||
"integrations": "Entegrasyonlar",
|
||||
"settings": "Ayarlar",
|
||||
"support": "Destek",
|
||||
"discussions": "Soru-cevap",
|
||||
"docs": "Dokümanlar",
|
||||
"changelog": "Değişiklik günlüğü",
|
||||
"profile": "Profil",
|
||||
"password": "Parola",
|
||||
"team": "Ekip",
|
||||
"logOut": "Çıkış yap",
|
||||
"notifications": ""
|
||||
"notifications": "Bildirimler"
|
||||
},
|
||||
"settingsEmail": "",
|
||||
"settingsEmailDescription": "",
|
||||
"settingsEmail": "Eposta",
|
||||
"settingsEmailDescription": "Sistem için eposta ayarlarını düzenleyin. Bu işlem eposta üzerinden bildirim ve alarm almak için gereklidir.",
|
||||
"settingsEmailHost": "",
|
||||
"settingsEmailPort": "",
|
||||
"settingsEmailAddress": "",
|
||||
@@ -490,73 +490,73 @@
|
||||
"port": ""
|
||||
},
|
||||
"common": {
|
||||
"appName": "",
|
||||
"appName": "Checkmate",
|
||||
"monitoringAgentName": "",
|
||||
"buttons": {
|
||||
"toggleTheme": ""
|
||||
},
|
||||
"toasts": {
|
||||
"networkError": "",
|
||||
"checkConnection": "",
|
||||
"unknownError": ""
|
||||
"checkConnection": "Lütfen bağlantınızı kontrol edin",
|
||||
"unknownError": "Bilinmeyen hata"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"common": {
|
||||
"navigation": {
|
||||
"continue": "",
|
||||
"back": ""
|
||||
"continue": "Devam et",
|
||||
"back": "Geri"
|
||||
},
|
||||
"inputs": {
|
||||
"email": {
|
||||
"label": "",
|
||||
"label": "Eposta",
|
||||
"placeholder": "",
|
||||
"errors": {
|
||||
"empty": "",
|
||||
"empty": "Devam etmek için eposta adresinizi girin",
|
||||
"invalid": ""
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"label": "",
|
||||
"label": "Parola",
|
||||
"rules": {
|
||||
"length": {
|
||||
"beginning": "",
|
||||
"highlighted": ""
|
||||
"highlighted": "8 karakter uzunluğunda"
|
||||
},
|
||||
"special": {
|
||||
"beginning": "",
|
||||
"highlighted": ""
|
||||
"beginning": "En az içermelidir: ",
|
||||
"highlighted": "bir özel karakter"
|
||||
},
|
||||
"number": {
|
||||
"beginning": "",
|
||||
"highlighted": ""
|
||||
"beginning": "En az içermelidir: ",
|
||||
"highlighted": "bir sayı"
|
||||
},
|
||||
"uppercase": {
|
||||
"beginning": "",
|
||||
"highlighted": ""
|
||||
"beginning": "En az içermelidir: ",
|
||||
"highlighted": "Bir büyük harf"
|
||||
},
|
||||
"lowercase": {
|
||||
"beginning": "",
|
||||
"highlighted": ""
|
||||
"beginning": "En az içermelidir: ",
|
||||
"highlighted": "Bir küçük harf"
|
||||
},
|
||||
"match": {
|
||||
"beginning": "",
|
||||
"highlighted": ""
|
||||
"highlighted": "eşleşmelidir"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"empty": "",
|
||||
"length": "",
|
||||
"uppercase": "",
|
||||
"lowercase": "",
|
||||
"number": "",
|
||||
"special": "",
|
||||
"incorrect": ""
|
||||
"empty": "Lütfen parolanızı girin",
|
||||
"length": "Parolanız en az 8 karakter uzunluğunda olmalıdır",
|
||||
"uppercase": "Parola en az 1 büyük harf içermelidir",
|
||||
"lowercase": "Parola en az 1 küçük harf içermelidir",
|
||||
"number": "Parola en az 1 sayı içermelidir",
|
||||
"special": "Parola en az 1 özel karakter içermelidir",
|
||||
"incorrect": "Parolanız sistemdeki ile uyuşmuyor"
|
||||
}
|
||||
},
|
||||
"passwordConfirm": {
|
||||
"label": "",
|
||||
"placeholder": "",
|
||||
"label": "Parolayı onayla",
|
||||
"placeholder": "Onaylamak için parolayı yeniden gir",
|
||||
"errors": {
|
||||
"empty": "",
|
||||
"different": ""
|
||||
@@ -572,78 +572,85 @@
|
||||
}
|
||||
},
|
||||
"lastName": {
|
||||
"label": "",
|
||||
"placeholder": "",
|
||||
"label": "Soyadı",
|
||||
"placeholder": "Ellis",
|
||||
"errors": {
|
||||
"empty": "",
|
||||
"length": "",
|
||||
"empty": "Lütfen soyadınızı girin",
|
||||
"length": "Soyadı en çok 50 karakter olmalıdır",
|
||||
"pattern": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
"heading": "",
|
||||
"subheadings": {
|
||||
"stepOne": "",
|
||||
"stepTwo": ""
|
||||
"stepOne": "Eposta adresinizi girin",
|
||||
"stepTwo": "Parolanızı girin"
|
||||
},
|
||||
"links": {
|
||||
"forgotPassword": "",
|
||||
"register": "",
|
||||
"forgotPasswordLink": "",
|
||||
"registerLink": ""
|
||||
"forgotPassword": "Parolanızı mı unuttunuz?",
|
||||
"register": "Hesabınız yok mu?",
|
||||
"forgotPasswordLink": "Parolayı sıfırla",
|
||||
"registerLink": "Buradan kayıt olun"
|
||||
},
|
||||
"toasts": {
|
||||
"success": "",
|
||||
"incorrectPassword": ""
|
||||
"success": "Tekrar hoşgeldiniz! Başarıyla sisteme giriş yaptınız.",
|
||||
"incorrectPassword": "Hatalı parola"
|
||||
},
|
||||
"errors": {
|
||||
"password": {
|
||||
"incorrect": ""
|
||||
"incorrect": "Giriş yaptığınız parola sistemdekiyle uyuşmuyor"
|
||||
}
|
||||
}
|
||||
},
|
||||
"registration": {
|
||||
"heading": {
|
||||
"superAdmin": "",
|
||||
"user": ""
|
||||
"superAdmin": "Süper yönetici oluştur",
|
||||
"user": "Kayıt ol"
|
||||
},
|
||||
"subheadings": {
|
||||
"stepOne": "",
|
||||
"stepTwo": "",
|
||||
"stepThree": ""
|
||||
"stepOne": "Kişisel bilgilerinizi girin",
|
||||
"stepTwo": "Eposta adresinizi girin",
|
||||
"stepThree": "Parolanızı oluturun"
|
||||
},
|
||||
"description": {
|
||||
"superAdmin": "",
|
||||
"superAdmin": "Başlamak için süper yönetici hesabı oluşturun",
|
||||
"user": ""
|
||||
},
|
||||
"gettingStartedButton": {
|
||||
"superAdmin": "",
|
||||
"superAdmin": "Süper yönetici hesabı oluşturun",
|
||||
"user": ""
|
||||
},
|
||||
"termsAndPolicies": "",
|
||||
"links": {
|
||||
"login": ""
|
||||
"login": "Bir hesabınız mı var? <a>Giriş yapın</a>"
|
||||
},
|
||||
"toasts": {
|
||||
"success": ""
|
||||
"success": "Hoşgeldiniz! Hesabınız başarıyla oluşturuldu."
|
||||
}
|
||||
},
|
||||
"forgotPassword": {
|
||||
"heading": "",
|
||||
"heading": "Parolanızı mı kaybettiniz?",
|
||||
"subheadings": {
|
||||
"stepOne": "",
|
||||
"stepTwo": "",
|
||||
"stepOne": "Endişelenmeyin, sıfırlamak için gerekli bilgileri göndereceğiz.",
|
||||
"stepTwo": "Parola sıfırlama için gerekli bilgileri <email/> hesabına ilettik.",
|
||||
"stepThree": "",
|
||||
"stepFour": ""
|
||||
},
|
||||
"buttons": {
|
||||
"openEmail": "",
|
||||
"resetPassword": ""
|
||||
"openEmail": "Eposta uygulamasını aç",
|
||||
"resetPassword": "Parolayı sıfırla"
|
||||
},
|
||||
"imageAlts": {
|
||||
"passwordKey": "",
|
||||
@@ -670,75 +677,76 @@
|
||||
"reconnected": "",
|
||||
"stillUnreachable": ""
|
||||
},
|
||||
"alertBox": "",
|
||||
"alertBox": "Sunucu bağlantı hatası",
|
||||
"description": "",
|
||||
"retryButton": {
|
||||
"default": "",
|
||||
"processing": ""
|
||||
"default": "Bağlantıyı tekrarla",
|
||||
"processing": "Bağlanıyor..."
|
||||
}
|
||||
}
|
||||
},
|
||||
"createNotifications": {
|
||||
"title": "",
|
||||
"title": "Bildirim kanalları oluştur",
|
||||
"nameSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"nameLabel": "",
|
||||
"namePlaceholder": ""
|
||||
"title": "İsim",
|
||||
"description": "Entegrasyon için açıklama",
|
||||
"nameLabel": "İsim",
|
||||
"namePlaceholder": "örn. Slack bildirimleri"
|
||||
},
|
||||
"typeSettings": {
|
||||
"title": "",
|
||||
"title": "Tür",
|
||||
"description": "",
|
||||
"typeLabel": ""
|
||||
"typeLabel": "Tür"
|
||||
},
|
||||
"emailSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"emailLabel": "",
|
||||
"emailPlaceholder": ""
|
||||
"title": "Eposta",
|
||||
"description": "Hedef eposta adresi",
|
||||
"emailLabel": "Eposta adresi",
|
||||
"emailPlaceholder": "örn. john@example.com"
|
||||
},
|
||||
"slackSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
"title": "Slack",
|
||||
"description": "Slack webhook'u burada tanımlayın",
|
||||
"webhookLabel": "Slack webhook adresi",
|
||||
"webhookPlaceholder": "https://hooks.slack.com/services/...\n"
|
||||
},
|
||||
"pagerdutySettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
"title": "PagerDuty",
|
||||
"description": "PagerDuty entegrasyonunu burada yapın",
|
||||
"integrationKeyLabel": "Entegrasyon anahtarı",
|
||||
"integrationKeyPlaceholder": "1234567890"
|
||||
},
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"title": "Discord",
|
||||
"description": "Discord webhook'u buradan ayarlayın",
|
||||
"webhookLabel": "Discord Webhook adresi",
|
||||
"webhookPlaceholder": "https://sunucu-adı.com/webhook\n"
|
||||
},
|
||||
"webhookSettings": {
|
||||
"title": "Webhook",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
"webhookPlaceholder": "https://sunucu-adı.com/webhook\n"
|
||||
}
|
||||
},
|
||||
"notificationConfig": {
|
||||
"title": "",
|
||||
"title": "Bildirimler",
|
||||
"description": ""
|
||||
},
|
||||
"monitorStatus": {
|
||||
"checkingEvery": "",
|
||||
"withCaptureAgent": "",
|
||||
"up": "",
|
||||
"down": "",
|
||||
"paused": ""
|
||||
"up": "ayakta",
|
||||
"down": "çalışmıyor",
|
||||
"paused": "beklemede"
|
||||
},
|
||||
"advancedMatching": "",
|
||||
"settingsEmailTLSServername": "",
|
||||
"settingsEmailIgnoreTLS": "",
|
||||
"settingsEmailRequireTLS": "",
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailSecure": "Güvenli - SSL kullan",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "Bildirimleri dene",
|
||||
"selectAll": "Tümünü seç"
|
||||
}
|
||||
@@ -583,6 +583,13 @@
|
||||
},
|
||||
"errors": {
|
||||
"validation": ""
|
||||
},
|
||||
"fields": {
|
||||
"password": {
|
||||
"errors": {
|
||||
"incorrect": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
@@ -709,13 +716,13 @@
|
||||
"integrationKeyLabel": "",
|
||||
"integrationKeyPlaceholder": ""
|
||||
},
|
||||
"genericWebhookSettings": {
|
||||
"discordSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
"webhookPlaceholder": ""
|
||||
},
|
||||
"discordSettings": {
|
||||
"webhookSettings": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"webhookLabel": "",
|
||||
@@ -740,5 +747,6 @@
|
||||
"settingsEmailRejectUnauthorized": "",
|
||||
"settingsEmailSecure": "",
|
||||
"settingsEmailPool": "",
|
||||
"sendTestNotifications": ""
|
||||
"sendTestNotifications": "",
|
||||
"selectAll": ""
|
||||
}
|
||||
@@ -21,6 +21,8 @@ services:
|
||||
volumes:
|
||||
- ./certbot/www/:/var/www/certbot/:rw
|
||||
- ./certbot/conf/:/etc/letsencrypt/:rw
|
||||
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot -w /var/www/certbot; sleep 12h & wait $${!}; done;'"
|
||||
|
||||
server:
|
||||
image: ghcr.io/bluewave-labs/checkmate:backend-demo
|
||||
restart: always
|
||||
@@ -29,21 +31,9 @@ services:
|
||||
env_file:
|
||||
- server.env
|
||||
depends_on:
|
||||
- redis
|
||||
- mongodb
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
redis:
|
||||
image: ghcr.io/bluewave-labs/checkmate:redis-demo
|
||||
restart: always
|
||||
volumes:
|
||||
- ./redis/data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 5s
|
||||
mongodb:
|
||||
image: ghcr.io/bluewave-labs/checkmate:mongo-demo
|
||||
restart: always
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { handleError } from "./controllerUtils.js";
|
||||
|
||||
const SERVICE_NAME = "JobQueueController";
|
||||
|
||||
class LogController {
|
||||
constructor(logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
getLogs = async (req, res, next) => {
|
||||
try {
|
||||
const logs = await this.logger.getLogs();
|
||||
res.success({
|
||||
msg: "Logs fetched successfully",
|
||||
data: logs,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getLogs"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
export default LogController;
|
||||
@@ -70,6 +70,10 @@ const StatusPageSchema = mongoose.Schema(
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showAdminLoginLink: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
@@ -153,6 +153,7 @@ const getStatusPage = async (url) => {
|
||||
showCharts: 1,
|
||||
showUptimePercentage: 1,
|
||||
timezone: 1,
|
||||
showAdminLoginLink: 1,
|
||||
url: 1,
|
||||
},
|
||||
monitors: {
|
||||
|
||||
@@ -36,6 +36,9 @@ import StatusPageController from "./controllers/statusPageController.js";
|
||||
import QueueRoutes from "./routes/queueRoute.js";
|
||||
import QueueController from "./controllers/queueController.js";
|
||||
|
||||
import LogRoutes from "./routes/logRoutes.js";
|
||||
import LogController from "./controllers/logController.js";
|
||||
|
||||
import NotificationRoutes from "./routes/notificationRoute.js";
|
||||
import NotificationController from "./controllers/notificationController.js";
|
||||
|
||||
@@ -294,6 +297,8 @@ const startApp = async () => {
|
||||
ServiceRegistry.get(StringService.SERVICE_NAME)
|
||||
);
|
||||
|
||||
const logController = new LogController(logger);
|
||||
|
||||
const statusPageController = new StatusPageController(
|
||||
ServiceRegistry.get(MongoDB.SERVICE_NAME),
|
||||
ServiceRegistry.get(StringService.SERVICE_NAME)
|
||||
@@ -320,6 +325,7 @@ const startApp = async () => {
|
||||
maintenanceWindowController
|
||||
);
|
||||
const queueRoutes = new QueueRoutes(queueController);
|
||||
const logRoutes = new LogRoutes(logController);
|
||||
const statusPageRoutes = new StatusPageRoutes(statusPageController);
|
||||
|
||||
const notificationRoutes = new NotificationRoutes(notificationController);
|
||||
@@ -372,6 +378,7 @@ const startApp = async () => {
|
||||
app.use("/api/v1/checks", verifyJWT, checkRoutes.getRouter());
|
||||
app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter());
|
||||
app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter());
|
||||
app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter());
|
||||
app.use("/api/v1/status-page", statusPageRoutes.getRouter());
|
||||
app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter());
|
||||
app.use("/api/v1/diagnostic", verifyJWT, diagnosticRoutes.getRouter());
|
||||
|
||||
@@ -8,6 +8,7 @@ const verifyOwnership = (Model, paramName) => {
|
||||
return async (req, res, next) => {
|
||||
const userId = req.user._id;
|
||||
const documentId = req.params[paramName];
|
||||
|
||||
try {
|
||||
const doc = await Model.findById(documentId);
|
||||
//If the document is not found, return a 404 error
|
||||
@@ -35,7 +36,7 @@ const verifyOwnership = (Model, paramName) => {
|
||||
|
||||
// If the userID does not match the document's userID, return a 403 error
|
||||
if (userId.toString() !== doc.userId.toString()) {
|
||||
const error = new Error(stringService.verifyOwnerUnauthorized);
|
||||
const error = new Error("Unauthorized");
|
||||
error.status = 403;
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
const SERVICE_NAME = "verifyTeamAccess";
|
||||
|
||||
const verifyTeamAccess = (Model, paramName) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const documentId = req.params[paramName];
|
||||
const doc = await Model.findById(documentId);
|
||||
|
||||
if (!doc) {
|
||||
const error = new Error("Document not found");
|
||||
error.status = 404;
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!req?.user?.teamId || !doc.teamId) {
|
||||
const error = new Error("Missing team information");
|
||||
error.status = 400;
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (req.user.teamId.toString() === doc.teamId.toString()) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
const error = new Error("Unauthorized");
|
||||
error.status = 403;
|
||||
throw error;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifyTeamAccess";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { verifyTeamAccess };
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
import { Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
class LogRoutes {
|
||||
constructor(logController) {
|
||||
this.router = Router();
|
||||
this.logController = logController;
|
||||
this.initRoutes();
|
||||
}
|
||||
initRoutes() {
|
||||
this.router.get("/", isAllowed(["admin", "superadmin"]), this.logController.getLogs);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
return this.router;
|
||||
}
|
||||
}
|
||||
|
||||
export default LogRoutes;
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Router } from "express";
|
||||
import { verifyOwnership } from "../middleware/verifyOwnership.js";
|
||||
import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js";
|
||||
import Monitor from "../db/models/Monitor.js";
|
||||
|
||||
import MaintenanceWindow from "../db/models/MaintenanceWindow.js";
|
||||
class MaintenanceWindowRoutes {
|
||||
constructor(maintenanceWindowController) {
|
||||
this.router = Router();
|
||||
@@ -24,9 +25,17 @@ class MaintenanceWindowRoutes {
|
||||
|
||||
this.router.get("/:id", this.maintenanceWindowController.getMaintenanceWindowById);
|
||||
|
||||
this.router.put("/:id", this.maintenanceWindowController.editMaintenanceWindow);
|
||||
this.router.put(
|
||||
"/:id",
|
||||
verifyTeamAccess(MaintenanceWindow, "id"),
|
||||
this.maintenanceWindowController.editMaintenanceWindow
|
||||
);
|
||||
|
||||
this.router.delete("/:id", this.maintenanceWindowController.deleteMaintenanceWindow);
|
||||
this.router.delete(
|
||||
"/:id",
|
||||
verifyTeamAccess(MaintenanceWindow, "id"),
|
||||
this.maintenanceWindowController.deleteMaintenanceWindow
|
||||
);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
@@ -2,7 +2,9 @@ import { Router } from "express";
|
||||
import { isAllowed } from "../middleware/isAllowed.js";
|
||||
import multer from "multer";
|
||||
import { fetchMonitorCertificate } from "../controllers/controllerUtils.js";
|
||||
|
||||
import Monitor from "../db/models/Monitor.js";
|
||||
import { verifyOwnership } from "../middleware/verifyOwnership.js";
|
||||
import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js";
|
||||
const upload = multer({
|
||||
storage: multer.memoryStorage(), // Store file in memory as Buffer
|
||||
});
|
||||
@@ -62,6 +64,7 @@ class MonitorRoutes {
|
||||
|
||||
this.router.delete(
|
||||
"/:monitorId",
|
||||
verifyOwnership(Monitor, "monitorId"),
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.monitorController.deleteMonitor
|
||||
);
|
||||
@@ -74,6 +77,7 @@ class MonitorRoutes {
|
||||
|
||||
this.router.put(
|
||||
"/:monitorId",
|
||||
verifyTeamAccess(Monitor, "monitorId"),
|
||||
isAllowed(["admin", "superadmin"]),
|
||||
this.monitorController.editMonitor
|
||||
);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Router } from "express";
|
||||
import { verifyJWT } from "../middleware/verifyJWT.js";
|
||||
|
||||
import { verifyOwnership } from "../middleware/verifyOwnership.js";
|
||||
import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js";
|
||||
import Notification from "../db/models/Notification.js";
|
||||
class NotificationRoutes {
|
||||
constructor(notificationController) {
|
||||
this.router = Router();
|
||||
@@ -18,10 +20,18 @@ class NotificationRoutes {
|
||||
|
||||
this.router.get("/team", this.notificationController.getNotificationsByTeamId);
|
||||
|
||||
this.router.delete("/:id", this.notificationController.deleteNotification);
|
||||
this.router.delete(
|
||||
"/:id",
|
||||
verifyOwnership(Notification, "id"),
|
||||
this.notificationController.deleteNotification
|
||||
);
|
||||
|
||||
this.router.get("/:id", this.notificationController.getNotificationById);
|
||||
this.router.put("/:id", this.notificationController.editNotification);
|
||||
this.router.put(
|
||||
"/:id",
|
||||
verifyTeamAccess(Notification, "id"),
|
||||
this.notificationController.editNotification
|
||||
);
|
||||
}
|
||||
|
||||
getRouter() {
|
||||
|
||||
+33
-18
@@ -4,6 +4,8 @@ dotenv.config();
|
||||
|
||||
class Logger {
|
||||
constructor() {
|
||||
this.logCache = [];
|
||||
this.maxCacheSize = 1000;
|
||||
const consoleFormat = format.printf(
|
||||
({ level, message, service, method, details, timestamp, stack }) => {
|
||||
if (message instanceof Object) {
|
||||
@@ -72,11 +74,9 @@ class Logger {
|
||||
* @param {Object} config.details - Additional details.
|
||||
*/
|
||||
info(config) {
|
||||
this.logger.info(config.message, {
|
||||
service: config.service,
|
||||
method: config.method,
|
||||
details: config.details,
|
||||
});
|
||||
const logEntry = this.buildLogEntry("info", config);
|
||||
this.cacheLog(logEntry);
|
||||
this.logger.info(config.message, logEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,11 +88,9 @@ class Logger {
|
||||
* @param {Object} config.details - Additional details.
|
||||
*/
|
||||
warn(config) {
|
||||
this.logger.warn(config.message, {
|
||||
service: config.service,
|
||||
method: config.method,
|
||||
details: config.details,
|
||||
});
|
||||
const logEntry = this.buildLogEntry("warn", config);
|
||||
this.cacheLog(logEntry);
|
||||
this.logger.warn(config.message, logEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,12 +102,9 @@ class Logger {
|
||||
* @param {Object} config.details - Additional details.
|
||||
*/
|
||||
error(config) {
|
||||
this.logger.error(config.message, {
|
||||
service: config.service,
|
||||
method: config.method,
|
||||
details: config.details,
|
||||
stack: config.stack,
|
||||
});
|
||||
const logEntry = this.buildLogEntry("error", config);
|
||||
this.cacheLog(logEntry);
|
||||
this.logger.error(config.message, logEntry);
|
||||
}
|
||||
/**
|
||||
* Logs a debug message.
|
||||
@@ -120,12 +115,32 @@ class Logger {
|
||||
* @param {Object} config.details - Additional details.
|
||||
*/
|
||||
debug(config) {
|
||||
this.logger.debug(config.message, {
|
||||
const logEntry = this.buildLogEntry("debug", config);
|
||||
this.cacheLog(logEntry);
|
||||
this.logger.debug(config.message, logEntry);
|
||||
}
|
||||
|
||||
cacheLog(entry) {
|
||||
this.logCache.push(entry);
|
||||
if (this.logCache.length > this.maxCacheSize) {
|
||||
this.logCache.shift();
|
||||
}
|
||||
}
|
||||
|
||||
getLogs() {
|
||||
return this.logCache;
|
||||
}
|
||||
|
||||
buildLogEntry(level, config) {
|
||||
return {
|
||||
level,
|
||||
message: config.message,
|
||||
service: config.service,
|
||||
method: config.method,
|
||||
details: config.details,
|
||||
stack: config.stack,
|
||||
});
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -463,6 +463,7 @@ const createStatusPageBodyValidation = joi.object({
|
||||
isPublished: joi.boolean(),
|
||||
showCharts: joi.boolean().optional(),
|
||||
showUptimePercentage: joi.boolean(),
|
||||
showAdminLoginLink: joi.boolean().optional(),
|
||||
});
|
||||
|
||||
const imageValidation = joi
|
||||
|
||||
Reference in new issue
Block a user