mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-18 09:26:56 +08:00
Compare commits
91 Commits
1.15.1
...
1.16.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
398219f847 | ||
|
7a50f0e3f3 | ||
|
4178b003a2 | ||
|
8ede6d888f | ||
|
cec0521834 | ||
|
73b603dd10 | ||
|
92a43e1f30 | ||
|
0cf395dfc3 | ||
|
749ca6f4a8 | ||
|
66971deaf4 | ||
|
8077744c60 | ||
|
c5faf709b8 | ||
|
7da9f139c1 | ||
|
7acbfd2474 | ||
|
9f493bbec7 | ||
|
5bf58cc6c4 | ||
|
d344914ca0 | ||
|
b680371746 | ||
|
e488e2dc0a | ||
|
4e3258579d | ||
|
aa8ea6d398 | ||
|
8b0813ceff | ||
|
91178ce6a5 | ||
|
429ad384d0 | ||
|
4b9dc2890d | ||
|
f9004bcbed | ||
|
bc174c3325 | ||
|
4c2753af46 | ||
|
c6ba5b621c | ||
|
96536ae391 | ||
|
ba46544772 | ||
|
5c852db1cf | ||
|
069d3765f0 | ||
|
15820c6937 | ||
|
000cbeb0ce | ||
|
e118d59ac8 | ||
|
39aa0a7f07 | ||
|
a12dffd1bc | ||
|
410805052e | ||
|
02a8147f22 | ||
|
d962ab7a1c | ||
|
63c8d24d6f | ||
|
254a6bfd36 | ||
|
29f3cbe8c6 | ||
|
53b98ad3e4 | ||
|
dbd7c087e0 | ||
|
272956025c | ||
|
db50ba91cc | ||
|
42ea3fb412 | ||
|
9f8b3151d8 | ||
|
73e38a13d2 | ||
|
369477b4b9 | ||
|
2347a01f7c | ||
|
c114c053d6 | ||
|
ae2c49a729 | ||
|
b9e72b9645 | ||
|
5a069b278d | ||
|
65ea2e6aeb | ||
|
e82fc1df61 | ||
|
7dd5f5ea0d | ||
|
45da7c5431 | ||
|
64a33d7455 | ||
|
e103ac8335 | ||
|
288ed1e3ca | ||
|
0765f05090 | ||
|
2638d68c97 | ||
|
1b1e0f6dd9 | ||
|
0961c6d9b3 | ||
|
ce7d8c38c5 | ||
|
454c1687cf | ||
|
28be32fc68 | ||
|
dd3992063e | ||
|
0313acd4c5 | ||
|
cd19b9fc49 | ||
|
c57b2c4d28 | ||
|
3dda5938f2 | ||
|
f00ec4dfef | ||
|
43f8fc701c | ||
|
499042504f | ||
|
faf6719e7c | ||
|
a9d264ccfc | ||
|
df8f93f0c2 | ||
|
28c0e16a0c | ||
|
6acc9546a0 | ||
|
f455e3a454 | ||
|
7abbf421d0 | ||
|
3625915a85 | ||
|
d74404e106 | ||
|
1c5bce8afa | ||
|
8b5997691e | ||
|
35360e2069 |
12
.github/workflows/auto-test.yml
vendored
12
.github/workflows/auto-test.yml
vendored
@@ -11,12 +11,14 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
auto-test:
|
auto-test:
|
||||||
|
needs: [ check-linters ]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
timeout-minutes: 15
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||||
node: [14, 16, 17]
|
node: [ 14, 16, 17, 18 ]
|
||||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -28,7 +30,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ matrix.node }}
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- run: npm run install-legacy
|
- run: npm install
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm test
|
- run: npm test
|
||||||
env:
|
env:
|
||||||
@@ -41,10 +43,10 @@ jobs:
|
|||||||
- run: git config --global core.autocrlf false # Mainly for Windows
|
- run: git config --global core.autocrlf false # Mainly for Windows
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Use Node.js LTS
|
- name: Use Node.js 14
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 14
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- run: npm run install-legacy
|
- run: npm install
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
|
@@ -8,7 +8,7 @@ services:
|
|||||||
image: louislam/uptime-kuma:1
|
image: louislam/uptime-kuma:1
|
||||||
container_name: uptime-kuma
|
container_name: uptime-kuma
|
||||||
volumes:
|
volumes:
|
||||||
- ./uptime-kuma:/app/data
|
- ./uptime-kuma-data:/app/data
|
||||||
ports:
|
ports:
|
||||||
- 3001:3001
|
- 3001:3001 # <Host Port>:<Container Port>
|
||||||
restart: always
|
restart: always
|
||||||
|
200
package-lock.json
generated
200
package-lock.json
generated
@@ -1,22 +1,23 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.15.0",
|
"version": "1.15.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.15.0",
|
"version": "1.15.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "~1.2.36",
|
"@fortawesome/fontawesome-svg-core": "~1.2.36",
|
||||||
"@fortawesome/free-regular-svg-icons": "~5.15.4",
|
"@fortawesome/free-regular-svg-icons": "~5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "~5.15.4",
|
"@fortawesome/free-solid-svg-icons": "~5.15.4",
|
||||||
"@fortawesome/vue-fontawesome": "~3.0.0-5",
|
"@fortawesome/vue-fontawesome": "~3.0.0-5",
|
||||||
"@louislam/sqlite3": "~15.0.3",
|
"@louislam/sqlite3": "~15.0.6",
|
||||||
"@popperjs/core": "~2.10.2",
|
"@popperjs/core": "~2.10.2",
|
||||||
"args-parser": "~1.3.0",
|
"args-parser": "~1.3.0",
|
||||||
"axios": "~0.26.1",
|
"axios": "~0.26.1",
|
||||||
|
"badge-maker": "^3.3.1",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
"bootstrap": "5.1.3",
|
"bootstrap": "5.1.3",
|
||||||
"bree": "~7.1.5",
|
"bree": "~7.1.5",
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
"chart.js": "~3.6.2",
|
"chart.js": "~3.6.2",
|
||||||
"chartjs-adapter-dayjs": "~1.0.0",
|
"chartjs-adapter-dayjs": "~1.0.0",
|
||||||
"check-password-strength": "^2.0.5",
|
"check-password-strength": "^2.0.5",
|
||||||
|
"chroma-js": "^2.1.2",
|
||||||
"command-exists": "~1.2.9",
|
"command-exists": "~1.2.9",
|
||||||
"compare-versions": "~3.6.0",
|
"compare-versions": "~3.6.0",
|
||||||
"dayjs": "~1.10.8",
|
"dayjs": "~1.10.8",
|
||||||
@@ -2697,9 +2699,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@louislam/sqlite3": {
|
"node_modules/@louislam/sqlite3": {
|
||||||
"version": "15.0.3",
|
"version": "15.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.0.6.tgz",
|
||||||
"integrity": "sha512-rCH6PIaa+TgBzpTRnqBKUa4H/5G2hIk5ukYK5rXxK+8hVGykRin3UMGzGejrPzIKzDnZGByIF0XD4ndi6lprRQ==",
|
"integrity": "sha512-+HF/4OEy+yakYzJlSPJbLDtf499t0s0eaglXC9y3Oa9OBZ+dKAaTW5+Ft1RCvfUJLFw/oyYjHtMsg9V+7NT05g==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/node-pre-gyp": "^1.0.0",
|
"@mapbox/node-pre-gyp": "^1.0.0",
|
||||||
@@ -3939,6 +3941,14 @@
|
|||||||
"url": "https://github.com/sponsors/epoberezkin"
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/anafanafo": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"char-width-table-consumer": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ansi-align": {
|
"node_modules/ansi-align": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
||||||
@@ -4366,6 +4376,22 @@
|
|||||||
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
||||||
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
||||||
},
|
},
|
||||||
|
"node_modules/badge-maker": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-OO/PS7Zg2E6qaUWzHEHt21Q5VjcFBAJVA8ztgT/fIdSZFBUwoyeo0ZhA6V5tUM8Vcjq8DJl6jfGhpjESssyqMQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"anafanafo": "2.0.0",
|
||||||
|
"css-color-converter": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"badge": "lib/badge-cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10",
|
||||||
|
"npm": ">= 5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -4443,6 +4469,11 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/binary-search": {
|
||||||
|
"version": "1.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz",
|
||||||
|
"integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA=="
|
||||||
|
},
|
||||||
"node_modules/bintrees": {
|
"node_modules/bintrees": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz",
|
||||||
@@ -4945,6 +4976,14 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/char-width-table-consumer": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"binary-search": "^1.3.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chardet": {
|
"node_modules/chardet": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz",
|
||||||
@@ -5004,6 +5043,29 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chroma-js": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-ri/ouYDWuxfus3UcaMxC1Tfp3IE9K5iQzxc2hSxbBRVNQFut1UuGAsZmiAf2mOUubzGJwgMSv9lHg+XqLaz1QQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"cross-env": "^6.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chroma-js/node_modules/cross-env": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==",
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": "^7.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"cross-env": "src/bin/cross-env.js",
|
||||||
|
"cross-env-shell": "src/bin/cross-env-shell.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ci-info": {
|
"node_modules/ci-info": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
|
||||||
@@ -5555,7 +5617,6 @@
|
|||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
"shebang-command": "^2.0.0",
|
"shebang-command": "^2.0.0",
|
||||||
@@ -5574,6 +5635,26 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-color-converter": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^0.5.2",
|
||||||
|
"color-name": "^1.1.4",
|
||||||
|
"css-unit-converter": "^1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-color-converter/node_modules/color-convert": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||||
|
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
|
||||||
|
},
|
||||||
|
"node_modules/css-color-converter/node_modules/color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
|
},
|
||||||
"node_modules/css-functions-list": {
|
"node_modules/css-functions-list": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz",
|
||||||
@@ -5583,6 +5664,11 @@
|
|||||||
"node": ">=12.22"
|
"node": ">=12.22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-unit-converter": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||||
|
},
|
||||||
"node_modules/cssesc": {
|
"node_modules/cssesc": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
@@ -8694,8 +8780,7 @@
|
|||||||
"node_modules/isexe": {
|
"node_modules/isexe": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
"devOptional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/isobject": {
|
"node_modules/isobject": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
@@ -13143,7 +13228,6 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -14689,7 +14773,6 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"shebang-regex": "^3.0.0"
|
"shebang-regex": "^3.0.0"
|
||||||
},
|
},
|
||||||
@@ -14701,7 +14784,6 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -16532,7 +16614,6 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
"devOptional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
},
|
},
|
||||||
@@ -18665,9 +18746,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@louislam/sqlite3": {
|
"@louislam/sqlite3": {
|
||||||
"version": "15.0.3",
|
"version": "15.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@louislam/sqlite3/-/sqlite3-15.0.6.tgz",
|
||||||
"integrity": "sha512-rCH6PIaa+TgBzpTRnqBKUa4H/5G2hIk5ukYK5rXxK+8hVGykRin3UMGzGejrPzIKzDnZGByIF0XD4ndi6lprRQ==",
|
"integrity": "sha512-+HF/4OEy+yakYzJlSPJbLDtf499t0s0eaglXC9y3Oa9OBZ+dKAaTW5+Ft1RCvfUJLFw/oyYjHtMsg9V+7NT05g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@mapbox/node-pre-gyp": "^1.0.0",
|
"@mapbox/node-pre-gyp": "^1.0.0",
|
||||||
"node-addon-api": "^4.2.0",
|
"node-addon-api": "^4.2.0",
|
||||||
@@ -19745,6 +19826,14 @@
|
|||||||
"uri-js": "^4.2.2"
|
"uri-js": "^4.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"anafanafo": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==",
|
||||||
|
"requires": {
|
||||||
|
"char-width-table-consumer": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ansi-align": {
|
"ansi-align": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
||||||
@@ -20087,6 +20176,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
||||||
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
|
||||||
},
|
},
|
||||||
|
"badge-maker": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-OO/PS7Zg2E6qaUWzHEHt21Q5VjcFBAJVA8ztgT/fIdSZFBUwoyeo0ZhA6V5tUM8Vcjq8DJl6jfGhpjESssyqMQ==",
|
||||||
|
"requires": {
|
||||||
|
"anafanafo": "2.0.0",
|
||||||
|
"css-color-converter": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -20143,6 +20241,11 @@
|
|||||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"binary-search": {
|
||||||
|
"version": "1.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz",
|
||||||
|
"integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA=="
|
||||||
|
},
|
||||||
"bintrees": {
|
"bintrees": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz",
|
||||||
@@ -20510,6 +20613,14 @@
|
|||||||
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
|
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"char-width-table-consumer": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==",
|
||||||
|
"requires": {
|
||||||
|
"binary-search": "^1.3.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chardet": {
|
"chardet": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz",
|
||||||
@@ -20551,6 +20662,24 @@
|
|||||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
|
||||||
},
|
},
|
||||||
|
"chroma-js": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-ri/ouYDWuxfus3UcaMxC1Tfp3IE9K5iQzxc2hSxbBRVNQFut1UuGAsZmiAf2mOUubzGJwgMSv9lHg+XqLaz1QQ==",
|
||||||
|
"requires": {
|
||||||
|
"cross-env": "^6.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cross-env": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==",
|
||||||
|
"requires": {
|
||||||
|
"cross-spawn": "^7.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ci-info": {
|
"ci-info": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
|
||||||
@@ -20993,7 +21122,6 @@
|
|||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
"shebang-command": "^2.0.0",
|
"shebang-command": "^2.0.0",
|
||||||
@@ -21006,12 +21134,39 @@
|
|||||||
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
|
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"css-color-converter": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==",
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^0.5.2",
|
||||||
|
"color-name": "^1.1.4",
|
||||||
|
"css-unit-converter": "^1.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||||
|
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"css-functions-list": {
|
"css-functions-list": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.0.1.tgz",
|
||||||
"integrity": "sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw==",
|
"integrity": "sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"css-unit-converter": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||||
|
},
|
||||||
"cssesc": {
|
"cssesc": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
@@ -23331,8 +23486,7 @@
|
|||||||
"isexe": {
|
"isexe": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||||
"devOptional": true
|
|
||||||
},
|
},
|
||||||
"isobject": {
|
"isobject": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
@@ -26732,8 +26886,7 @@
|
|||||||
"path-key": {
|
"path-key": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"path-parse": {
|
"path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
@@ -27893,7 +28046,6 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"shebang-regex": "^3.0.0"
|
"shebang-regex": "^3.0.0"
|
||||||
}
|
}
|
||||||
@@ -27901,8 +28053,7 @@
|
|||||||
"shebang-regex": {
|
"shebang-regex": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"signal-exit": {
|
"signal-exit": {
|
||||||
"version": "3.0.7",
|
"version": "3.0.7",
|
||||||
@@ -29304,7 +29455,6 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
"devOptional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
10
package.json
10
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.15.1",
|
"version": "1.16.0-beta.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
"node": "14.* || >=16.*"
|
"node": "14.* || >=16.*"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"install-legacy": "npm install --legacy-peer-deps",
|
"install-legacy": "npm install",
|
||||||
"update-legacy": "npm update --legacy-peer-deps",
|
"update-legacy": "npm update",
|
||||||
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
||||||
"lint-fix:js": "eslint --ext \".js,.vue\" --fix --ignore-path .gitignore .",
|
"lint-fix:js": "eslint --ext \".js,.vue\" --fix --ignore-path .gitignore .",
|
||||||
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
||||||
@@ -64,10 +64,11 @@
|
|||||||
"@fortawesome/free-regular-svg-icons": "~5.15.4",
|
"@fortawesome/free-regular-svg-icons": "~5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "~5.15.4",
|
"@fortawesome/free-solid-svg-icons": "~5.15.4",
|
||||||
"@fortawesome/vue-fontawesome": "~3.0.0-5",
|
"@fortawesome/vue-fontawesome": "~3.0.0-5",
|
||||||
"@louislam/sqlite3": "~15.0.3",
|
"@louislam/sqlite3": "~15.0.6",
|
||||||
"@popperjs/core": "~2.10.2",
|
"@popperjs/core": "~2.10.2",
|
||||||
"args-parser": "~1.3.0",
|
"args-parser": "~1.3.0",
|
||||||
"axios": "~0.26.1",
|
"axios": "~0.26.1",
|
||||||
|
"badge-maker": "^3.3.1",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
"bootstrap": "5.1.3",
|
"bootstrap": "5.1.3",
|
||||||
"bree": "~7.1.5",
|
"bree": "~7.1.5",
|
||||||
@@ -75,6 +76,7 @@
|
|||||||
"chart.js": "~3.6.2",
|
"chart.js": "~3.6.2",
|
||||||
"chartjs-adapter-dayjs": "~1.0.0",
|
"chartjs-adapter-dayjs": "~1.0.0",
|
||||||
"check-password-strength": "^2.0.5",
|
"check-password-strength": "^2.0.5",
|
||||||
|
"chroma-js": "^2.1.2",
|
||||||
"command-exists": "~1.2.9",
|
"command-exists": "~1.2.9",
|
||||||
"compare-versions": "~3.6.0",
|
"compare-versions": "~3.6.0",
|
||||||
"dayjs": "~1.10.8",
|
"dayjs": "~1.10.8",
|
||||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
@@ -1,7 +1,20 @@
|
|||||||
const args = require("args-parser")(process.argv);
|
const args = require("args-parser")(process.argv);
|
||||||
const demoMode = args["demo"] || false;
|
const demoMode = args["demo"] || false;
|
||||||
|
|
||||||
|
const badgeConstants = {
|
||||||
|
naColor: "#999",
|
||||||
|
defaultUpColor: "#66c20a",
|
||||||
|
defaultDownColor: "#c2290a",
|
||||||
|
defaultPingColor: "blue", // as defined by badge-maker / shields.io
|
||||||
|
defaultStyle: "flat",
|
||||||
|
defaultPingValueSuffix: "ms",
|
||||||
|
defaultPingLabelSuffix: "h",
|
||||||
|
defaultUptimeValueSuffix: "%",
|
||||||
|
defaultUptimeLabelSuffix: "h",
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
args,
|
args,
|
||||||
demoMode
|
demoMode,
|
||||||
|
badgeConstants,
|
||||||
};
|
};
|
||||||
|
@@ -7,7 +7,7 @@ dayjs.extend(timezone);
|
|||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const { Prometheus } = require("../prometheus");
|
const { Prometheus } = require("../prometheus");
|
||||||
const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
|
const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
|
||||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, errorLog, mqttAsync } = require("../util-server");
|
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mqttAsync } = require("../util-server");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
const { Notification } = require("../notification");
|
const { Notification } = require("../notification");
|
||||||
@@ -15,6 +15,7 @@ const { Proxy } = require("../proxy");
|
|||||||
const { demoMode } = require("../config");
|
const { demoMode } = require("../config");
|
||||||
const version = require("../../package.json").version;
|
const version = require("../../package.json").version;
|
||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
|
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* status:
|
* status:
|
||||||
@@ -181,7 +182,7 @@ class Monitor extends BeanModel {
|
|||||||
// undefined if not https
|
// undefined if not https
|
||||||
let tlsInfo = undefined;
|
let tlsInfo = undefined;
|
||||||
|
|
||||||
if (!previousBeat) {
|
if (!previousBeat || this.type === "push") {
|
||||||
previousBeat = await R.findOne("heartbeat", " monitor_id = ? ORDER BY time DESC", [
|
previousBeat = await R.findOne("heartbeat", " monitor_id = ? ORDER BY time DESC", [
|
||||||
this.id,
|
this.id,
|
||||||
]);
|
]);
|
||||||
@@ -376,9 +377,6 @@ class Monitor extends BeanModel {
|
|||||||
log.debug("monitor", "heartbeatCount" + heartbeatCount + " " + time);
|
log.debug("monitor", "heartbeatCount" + heartbeatCount + " " + time);
|
||||||
|
|
||||||
if (heartbeatCount <= 0) {
|
if (heartbeatCount <= 0) {
|
||||||
// Fix #922, since previous heartbeat could be inserted by api, it should get from database
|
|
||||||
previousBeat = await Monitor.getPreviousHeartbeat(this.id);
|
|
||||||
|
|
||||||
throw new Error("No heartbeat in the time window");
|
throw new Error("No heartbeat in the time window");
|
||||||
} else {
|
} else {
|
||||||
// No need to insert successful heartbeat for push type, so end here
|
// No need to insert successful heartbeat for push type, so end here
|
||||||
@@ -521,7 +519,7 @@ class Monitor extends BeanModel {
|
|||||||
await beat();
|
await beat();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.trace(e);
|
console.trace(e);
|
||||||
errorLog(e, false);
|
UptimeKumaServer.errorLog(e, false);
|
||||||
log.error("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues");
|
log.error("monitor", "Please report to https://github.com/louislam/uptime-kuma/issues");
|
||||||
|
|
||||||
if (! this.isStop) {
|
if (! this.isStop) {
|
||||||
|
@@ -93,8 +93,23 @@ class AliyunSMS extends NotificationProvider {
|
|||||||
param2[key] = param[key];
|
param2[key] = param[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Escape more characters than encodeURIComponent does.
|
||||||
|
// For generating Aliyun signature, all characters except A-Za-z0-9~-._ are encoded.
|
||||||
|
// See https://help.aliyun.com/document_detail/315526.html
|
||||||
|
// This encoding methods as known as RFC 3986 (https://tools.ietf.org/html/rfc3986)
|
||||||
|
let moreEscapesTable = function (m) {
|
||||||
|
return {
|
||||||
|
"!": "%21",
|
||||||
|
"*": "%2A",
|
||||||
|
"'": "%27",
|
||||||
|
"(": "%28",
|
||||||
|
")": "%29"
|
||||||
|
}[m];
|
||||||
|
};
|
||||||
|
|
||||||
for (let key in param2) {
|
for (let key in param2) {
|
||||||
data.push(`${encodeURIComponent(key)}=${encodeURIComponent(param2[key])}`);
|
let value = encodeURIComponent(param2[key]).replace(/[!*'()]/g, moreEscapesTable);
|
||||||
|
data.push(`${encodeURIComponent(key)}=${value}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let StringToSign = `POST&${encodeURIComponent("/")}&${encodeURIComponent(data.join("&"))}`;
|
let StringToSign = `POST&${encodeURIComponent("/")}&${encodeURIComponent(data.join("&"))}`;
|
||||||
|
@@ -6,9 +6,14 @@ class Apprise extends NotificationProvider {
|
|||||||
name = "apprise";
|
name = "apprise";
|
||||||
|
|
||||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
let s = childProcess.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL ]);
|
const args = [ "-vv", "-b", msg, notification.appriseURL ];
|
||||||
|
if (notification.title) {
|
||||||
|
args.push("-t");
|
||||||
|
args.push(notification.title);
|
||||||
|
}
|
||||||
|
const s = childProcess.spawnSync("apprise", args);
|
||||||
|
|
||||||
let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
|
const output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
|
||||||
|
|
||||||
if (output) {
|
if (output) {
|
||||||
|
|
||||||
|
@@ -22,16 +22,23 @@ class Discord extends NotificationProvider {
|
|||||||
return okMsg;
|
return okMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url;
|
let address;
|
||||||
|
|
||||||
if (monitorJSON["type"] === "port") {
|
switch (monitorJSON["type"]) {
|
||||||
url = monitorJSON["hostname"];
|
case "ping":
|
||||||
if (monitorJSON["port"]) {
|
address = monitorJSON["hostname"];
|
||||||
url += ":" + monitorJSON["port"];
|
break;
|
||||||
}
|
case "port":
|
||||||
|
case "dns":
|
||||||
} else {
|
case "steam":
|
||||||
url = monitorJSON["url"];
|
address = monitorJSON["hostname"];
|
||||||
|
if (monitorJSON["port"]) {
|
||||||
|
address += ":" + monitorJSON["port"];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
address = monitorJSON["url"];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
||||||
@@ -48,8 +55,8 @@ class Discord extends NotificationProvider {
|
|||||||
value: monitorJSON["name"],
|
value: monitorJSON["name"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Service URL",
|
name: "Service URL / Address",
|
||||||
value: url,
|
value: address,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Time (UTC)",
|
name: "Time (UTC)",
|
||||||
@@ -84,7 +91,7 @@ class Discord extends NotificationProvider {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Service URL",
|
name: "Service URL",
|
||||||
value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url,
|
value: address.startsWith("http") ? "[Visit Service](" + address + ")" : address,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Time (UTC)",
|
name: "Time (UTC)",
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
let express = require("express");
|
let express = require("express");
|
||||||
const { allowDevAllOrigin } = require("../util-server");
|
const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin } = require("../util-server");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
const Monitor = require("../model/monitor");
|
const Monitor = require("../model/monitor");
|
||||||
@@ -7,6 +7,9 @@ const dayjs = require("dayjs");
|
|||||||
const { UP, DOWN, flipStatus, log } = require("../../src/util");
|
const { UP, DOWN, flipStatus, log } = require("../../src/util");
|
||||||
const StatusPage = require("../model/status_page");
|
const StatusPage = require("../model/status_page");
|
||||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||||
|
const { makeBadge } = require("badge-maker");
|
||||||
|
const { badgeConstants } = require("../config");
|
||||||
|
|
||||||
let router = express.Router();
|
let router = express.Router();
|
||||||
|
|
||||||
let cache = apicache.middleware;
|
let cache = apicache.middleware;
|
||||||
@@ -197,6 +200,182 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response) => {
|
||||||
|
allowAllOrigin(response);
|
||||||
|
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
upLabel = "Up",
|
||||||
|
downLabel = "Down",
|
||||||
|
upColor = badgeConstants.defaultUpColor,
|
||||||
|
downColor = badgeConstants.defaultDownColor,
|
||||||
|
style = badgeConstants.defaultStyle,
|
||||||
|
value, // for demo purpose only
|
||||||
|
} = request.query;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const requestedMonitorId = parseInt(request.params.id, 10);
|
||||||
|
const overrideValue = value !== undefined ? parseInt(value) : undefined;
|
||||||
|
|
||||||
|
let publicMonitor = await R.getRow(`
|
||||||
|
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
||||||
|
WHERE monitor_group.group_id = \`group\`.id
|
||||||
|
AND monitor_group.monitor_id = ?
|
||||||
|
AND public = 1
|
||||||
|
`,
|
||||||
|
[ requestedMonitorId ]
|
||||||
|
);
|
||||||
|
|
||||||
|
const badgeValues = { style };
|
||||||
|
|
||||||
|
if (!publicMonitor) {
|
||||||
|
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
|
||||||
|
|
||||||
|
badgeValues.message = "N/A";
|
||||||
|
badgeValues.color = badgeConstants.naColor;
|
||||||
|
} else {
|
||||||
|
const heartbeat = await Monitor.getPreviousHeartbeat(requestedMonitorId);
|
||||||
|
const state = overrideValue !== undefined ? overrideValue : heartbeat.status === 1;
|
||||||
|
|
||||||
|
badgeValues.color = state ? upColor : downColor;
|
||||||
|
badgeValues.message = label ?? state ? upLabel : downLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the svg based on given values
|
||||||
|
const svg = makeBadge(badgeValues);
|
||||||
|
|
||||||
|
response.type("image/svg+xml");
|
||||||
|
response.send(svg);
|
||||||
|
} catch (error) {
|
||||||
|
send403(response, error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (request, response) => {
|
||||||
|
allowAllOrigin(response);
|
||||||
|
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
labelPrefix,
|
||||||
|
labelSuffix = badgeConstants.defaultUptimeLabelSuffix,
|
||||||
|
prefix,
|
||||||
|
suffix = badgeConstants.defaultUptimeValueSuffix,
|
||||||
|
color,
|
||||||
|
labelColor,
|
||||||
|
style = badgeConstants.defaultStyle,
|
||||||
|
value, // for demo purpose only
|
||||||
|
} = request.query;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const requestedMonitorId = parseInt(request.params.id, 10);
|
||||||
|
// if no duration is given, set value to 24 (h)
|
||||||
|
const requestedDuration = request.params.duration !== undefined ? parseInt(request.params.duration, 10) : 24;
|
||||||
|
const overrideValue = value && parseFloat(value);
|
||||||
|
|
||||||
|
let publicMonitor = await R.getRow(`
|
||||||
|
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
||||||
|
WHERE monitor_group.group_id = \`group\`.id
|
||||||
|
AND monitor_group.monitor_id = ?
|
||||||
|
AND public = 1
|
||||||
|
`,
|
||||||
|
[ requestedMonitorId ]
|
||||||
|
);
|
||||||
|
|
||||||
|
const badgeValues = { style };
|
||||||
|
|
||||||
|
if (!publicMonitor) {
|
||||||
|
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
|
||||||
|
badgeValues.message = "N/A";
|
||||||
|
badgeValues.color = badgeConstants.naColor;
|
||||||
|
} else {
|
||||||
|
const uptime = overrideValue ?? await Monitor.calcUptime(
|
||||||
|
requestedDuration,
|
||||||
|
requestedMonitorId
|
||||||
|
);
|
||||||
|
|
||||||
|
// limit the displayed uptime percentage to four (two, when displayed as percent) decimal digits
|
||||||
|
const cleanUptime = parseFloat(uptime.toPrecision(4));
|
||||||
|
|
||||||
|
// use a given, custom color or calculate one based on the uptime value
|
||||||
|
badgeValues.color = color ?? percentageToColor(uptime);
|
||||||
|
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||||
|
badgeValues.labelColor = labelColor ?? "";
|
||||||
|
// build a lable string. If a custom label is given, override the default one (requestedDuration)
|
||||||
|
badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
|
||||||
|
badgeValues.message = filterAndJoin([ prefix, `${cleanUptime * 100}`, suffix ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the SVG based on given values
|
||||||
|
const svg = makeBadge(badgeValues);
|
||||||
|
|
||||||
|
response.type("image/svg+xml");
|
||||||
|
response.send(svg);
|
||||||
|
} catch (error) {
|
||||||
|
send403(response, error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, response) => {
|
||||||
|
allowAllOrigin(response);
|
||||||
|
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
labelPrefix,
|
||||||
|
labelSuffix = badgeConstants.defaultPingLabelSuffix,
|
||||||
|
prefix,
|
||||||
|
suffix = badgeConstants.defaultPingValueSuffix,
|
||||||
|
color = badgeConstants.defaultPingColor,
|
||||||
|
labelColor,
|
||||||
|
style = badgeConstants.defaultStyle,
|
||||||
|
value, // for demo purpose only
|
||||||
|
} = request.query;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const requestedMonitorId = parseInt(request.params.id, 10);
|
||||||
|
|
||||||
|
// Default duration is 24 (h) if not defined in queryParam, limited to 720h (30d)
|
||||||
|
const requestedDuration = Math.min(request.params.duration ? parseInt(request.params.duration, 10) : 24, 720);
|
||||||
|
const overrideValue = value && parseFloat(value);
|
||||||
|
|
||||||
|
const publicAvgPing = parseInt(await R.getCell(`
|
||||||
|
SELECT AVG(ping) FROM monitor_group, \`group\`, heartbeat
|
||||||
|
WHERE monitor_group.group_id = \`group\`.id
|
||||||
|
AND heartbeat.time > DATETIME('now', ? || ' hours')
|
||||||
|
AND heartbeat.ping IS NOT NULL
|
||||||
|
AND public = 1
|
||||||
|
AND heartbeat.monitor_id = ?
|
||||||
|
`,
|
||||||
|
[ -requestedDuration, requestedMonitorId ]
|
||||||
|
));
|
||||||
|
|
||||||
|
const badgeValues = { style };
|
||||||
|
|
||||||
|
if (!publicAvgPing) {
|
||||||
|
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
|
||||||
|
|
||||||
|
badgeValues.message = "N/A";
|
||||||
|
badgeValues.color = badgeConstants.naColor;
|
||||||
|
} else {
|
||||||
|
const avgPing = parseInt(overrideValue ?? publicAvgPing);
|
||||||
|
|
||||||
|
badgeValues.color = color;
|
||||||
|
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||||
|
badgeValues.labelColor = labelColor ?? "";
|
||||||
|
// build a lable string. If a custom label is given, override the default one (requestedDuration)
|
||||||
|
badgeValues.label = filterAndJoin([ labelPrefix, label ?? requestedDuration, labelSuffix ]);
|
||||||
|
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the SVG based on given values
|
||||||
|
const svg = makeBadge(badgeValues);
|
||||||
|
|
||||||
|
response.type("image/svg+xml");
|
||||||
|
response.send(svg);
|
||||||
|
} catch (error) {
|
||||||
|
send403(response, error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a 403 response
|
* Send a 403 response
|
||||||
* @param {Object} res Express response object
|
* @param {Object} res Express response object
|
||||||
|
@@ -60,7 +60,7 @@ log.info("server", "Importing this project modules");
|
|||||||
log.debug("server", "Importing Monitor");
|
log.debug("server", "Importing Monitor");
|
||||||
const Monitor = require("./model/monitor");
|
const Monitor = require("./model/monitor");
|
||||||
log.debug("server", "Importing Settings");
|
log.debug("server", "Importing Settings");
|
||||||
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, errorLog, doubleCheckPassword } = require("./util-server");
|
const { getSettings, setSettings, setting, initJWTSecret, checkLogin, startUnitTest, FBSD, doubleCheckPassword } = require("./util-server");
|
||||||
|
|
||||||
log.debug("server", "Importing Notification");
|
log.debug("server", "Importing Notification");
|
||||||
const { Notification } = require("./notification");
|
const { Notification } = require("./notification");
|
||||||
@@ -1694,6 +1694,6 @@ gracefulShutdown(server.httpServer, {
|
|||||||
// Catch unexpected errors here
|
// Catch unexpected errors here
|
||||||
process.addListener("unhandledRejection", (error, promise) => {
|
process.addListener("unhandledRejection", (error, promise) => {
|
||||||
console.trace(error);
|
console.trace(error);
|
||||||
errorLog(error, false);
|
UptimeKumaServer.errorLog(error, false);
|
||||||
console.error("If you keep encountering errors, please report to https://github.com/louislam/uptime-kuma/issues");
|
console.error("If you keep encountering errors, please report to https://github.com/louislam/uptime-kuma/issues");
|
||||||
});
|
});
|
||||||
|
@@ -5,13 +5,14 @@ const http = require("http");
|
|||||||
const { Server } = require("socket.io");
|
const { Server } = require("socket.io");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { log } = require("../src/util");
|
const { log } = require("../src/util");
|
||||||
|
const Database = require("./database");
|
||||||
|
const util = require("util");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue.
|
* `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue.
|
||||||
* @type {UptimeKumaServer}
|
* @type {UptimeKumaServer}
|
||||||
*/
|
*/
|
||||||
class UptimeKumaServer {
|
class UptimeKumaServer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {UptimeKumaServer}
|
* @type {UptimeKumaServer}
|
||||||
@@ -83,6 +84,32 @@ class UptimeKumaServer {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write error to log file
|
||||||
|
* @param {any} error The error to write
|
||||||
|
* @param {boolean} outputToConsole Should the error also be output to console?
|
||||||
|
*/
|
||||||
|
static errorLog(error, outputToConsole = true) {
|
||||||
|
const errorLogStream = fs.createWriteStream(Database.dataDir + "/error.log", {
|
||||||
|
flags: "a"
|
||||||
|
});
|
||||||
|
|
||||||
|
errorLogStream.on("error", () => {
|
||||||
|
log.info("", "Cannot write to error.log");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (errorLogStream) {
|
||||||
|
const dateTime = R.isoDateTime();
|
||||||
|
errorLogStream.write(`[${dateTime}] ` + util.format(error) + "\n");
|
||||||
|
|
||||||
|
if (outputToConsole) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorLogStream.end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@@ -7,9 +7,9 @@ const { Resolver } = require("dns");
|
|||||||
const childProcess = require("child_process");
|
const childProcess = require("child_process");
|
||||||
const iconv = require("iconv-lite");
|
const iconv = require("iconv-lite");
|
||||||
const chardet = require("chardet");
|
const chardet = require("chardet");
|
||||||
const fs = require("fs");
|
|
||||||
const nodeJsUtil = require("util");
|
|
||||||
const mqtt = require("mqtt");
|
const mqtt = require("mqtt");
|
||||||
|
const chroma = require("chroma-js");
|
||||||
|
const { badgeConstants } = require("./config");
|
||||||
|
|
||||||
// From ping-lite
|
// From ping-lite
|
||||||
exports.WIN = /^win/.test(process.platform);
|
exports.WIN = /^win/.test(process.platform);
|
||||||
@@ -206,7 +206,7 @@ exports.dnsResolve = function (hostname, resolverServer, rrtype) {
|
|||||||
/**
|
/**
|
||||||
* Retrieve value of setting based on key
|
* Retrieve value of setting based on key
|
||||||
* @param {string} key Key of setting to retrieve
|
* @param {string} key Key of setting to retrieve
|
||||||
* @returns {Promise<Object>} Object representation of setting
|
* @returns {Promise<any>} Value
|
||||||
*/
|
*/
|
||||||
exports.setting = async function (key) {
|
exports.setting = async function (key) {
|
||||||
let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
|
let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
|
||||||
@@ -525,28 +525,32 @@ exports.convertToUTF8 = (body) => {
|
|||||||
return str.toString();
|
return str.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
let logFile;
|
/**
|
||||||
|
* Returns a color code in hex format based on a given percentage:
|
||||||
try {
|
* 0% => hue = 10 => red
|
||||||
logFile = fs.createWriteStream("./data/error.log", {
|
* 100% => hue = 90 => green
|
||||||
flags: "a"
|
*
|
||||||
});
|
* @param {number} percentage float, 0 to 1
|
||||||
} catch (_) { }
|
* @param {number} maxHue
|
||||||
|
* @param {number} minHue, int
|
||||||
|
* @returns {string}, hex value
|
||||||
|
*/
|
||||||
|
exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => {
|
||||||
|
const hue = percentage * (maxHue - minHue) + minHue;
|
||||||
|
try {
|
||||||
|
return chroma(`hsl(${hue}, 90%, 40%)`).hex();
|
||||||
|
} catch (err) {
|
||||||
|
return badgeConstants.naColor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write error to log file
|
* Joins and array of string to one string after filtering out empty values
|
||||||
* @param {any} error The error to write
|
*
|
||||||
* @param {boolean} outputToConsole Should the error also be output to console?
|
* @param {string[]} parts
|
||||||
|
* @param {string} connector
|
||||||
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
exports.errorLog = (error, outputToConsole = true) => {
|
exports.filterAndJoin = (parts, connector = "") => {
|
||||||
try {
|
return parts.filter((part) => !!part && part !== "").join(connector);
|
||||||
if (logFile) {
|
|
||||||
const dateTime = R.isoDateTime();
|
|
||||||
logFile.write(`[${dateTime}] ` + nodeJsUtil.format(error) + "\n");
|
|
||||||
|
|
||||||
if (outputToConsole) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (_) { }
|
|
||||||
};
|
};
|
||||||
|
@@ -367,7 +367,7 @@ textarea.form-control {
|
|||||||
.item {
|
.item {
|
||||||
display: block;
|
display: block;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
padding: 13px 15px 10px 15px;
|
padding: 15px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
transition: all ease-in-out 0.15s;
|
transition: all ease-in-out 0.15s;
|
||||||
|
|
||||||
|
@@ -10,7 +10,10 @@ import { sleep } from "../util.ts";
|
|||||||
export default {
|
export default {
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
value: [ String, Number ],
|
value: {
|
||||||
|
type: [ String, Number ],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
time: {
|
time: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0.3,
|
default: 0.3,
|
||||||
|
@@ -13,7 +13,10 @@ dayjs.extend(relativeTime);
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: String,
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
dateOnly: {
|
dateOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="wrap" class="wrap" :style="wrapStyle">
|
<div ref="wrap" class="wrap" :style="wrapStyle">
|
||||||
<div class="hp-bar-big" :style="barStyle">
|
<div class="hp-bar-big d-flex" :style="barStyle">
|
||||||
<div
|
<div
|
||||||
v-for="(beat, index) in shortBeatList"
|
v-for="(beat, index) in shortBeatList"
|
||||||
:key="index"
|
:key="index"
|
||||||
@@ -8,7 +8,11 @@
|
|||||||
:class="{ 'empty' : (beat === 0), 'down' : (beat.status === 0), 'pending' : (beat.status === 2) }"
|
:class="{ 'empty' : (beat === 0), 'down' : (beat.status === 0), 'pending' : (beat.status === 2) }"
|
||||||
:style="beatStyle"
|
:style="beatStyle"
|
||||||
:title="getBeatTitle(beat)"
|
:title="getBeatTitle(beat)"
|
||||||
/>
|
@mouseenter="toggleActivateSibling"
|
||||||
|
@mouseleave="toggleActivateSibling"
|
||||||
|
>
|
||||||
|
<div class="beat-inner" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -168,6 +172,29 @@ export default {
|
|||||||
|
|
||||||
getBeatTitle(beat) {
|
getBeatTitle(beat) {
|
||||||
return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : "");
|
return `${this.$root.datetime(beat.time)}` + ((beat.msg) ? ` - ${beat.msg}` : "");
|
||||||
|
},
|
||||||
|
|
||||||
|
// Toggling the activeSibling class on hover over the current hover item
|
||||||
|
toggleActivateSibling(e) {
|
||||||
|
// Variable definition
|
||||||
|
const element = e.target;
|
||||||
|
const previous = element.previousSibling;
|
||||||
|
const next = element.nextSibling;
|
||||||
|
|
||||||
|
// Return if the hovered element has empty class
|
||||||
|
if (element.classList.contains("empty")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if Previous Sibling is heartbar element and doesn't have the empty class
|
||||||
|
if (previous.children && !previous.classList.contains("empty")) {
|
||||||
|
previous.classList.toggle("active-sibling");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if Next Sibling is heartbar element and doesn't have the empty class
|
||||||
|
if (next.children && !next.classList.contains("empty")) {
|
||||||
|
next.classList.toggle("active-sibling");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -184,9 +211,10 @@ export default {
|
|||||||
|
|
||||||
.hp-bar-big {
|
.hp-bar-big {
|
||||||
.beat {
|
.beat {
|
||||||
display: inline-block;
|
|
||||||
background-color: $primary;
|
background-color: $primary;
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
|
display: inline-block;
|
||||||
|
transition: all ease 0.6s;
|
||||||
|
|
||||||
&.empty {
|
&.empty {
|
||||||
background-color: aliceblue;
|
background-color: aliceblue;
|
||||||
@@ -200,11 +228,23 @@ export default {
|
|||||||
background-color: $warning;
|
background-color: $warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.beat-inner {
|
||||||
|
border-radius: $border-radius;
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
&:not(.empty):hover {
|
&:not(.empty):hover {
|
||||||
transition: all ease-in-out 0.15s;
|
transition: all ease 0.15s;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
transform: scale(var(--hover-scale));
|
transform: scale(var(--hover-scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.active-sibling {
|
||||||
|
transform: scale(1.15);
|
||||||
|
transition: all ease 0.15s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@ import timezone from "dayjs/plugin/timezone";
|
|||||||
import utc from "dayjs/plugin/utc";
|
import utc from "dayjs/plugin/utc";
|
||||||
import { LineChart } from "vue-chart-3";
|
import { LineChart } from "vue-chart-3";
|
||||||
import { useToast } from "vue-toastification";
|
import { useToast } from "vue-toastification";
|
||||||
import { DOWN } from "../util.ts";
|
import { DOWN, log } from "../util.ts";
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
@@ -217,8 +217,9 @@ export default {
|
|||||||
watch: {
|
watch: {
|
||||||
// Update chart data when the selected chart period changes
|
// Update chart data when the selected chart period changes
|
||||||
chartPeriodHrs: function (newPeriod) {
|
chartPeriodHrs: function (newPeriod) {
|
||||||
if (newPeriod === "0") {
|
|
||||||
newPeriod = null;
|
// eslint-disable-next-line eqeqeq
|
||||||
|
if (newPeriod == "0") {
|
||||||
this.heartbeatList = null;
|
this.heartbeatList = null;
|
||||||
this.$root.storage().removeItem(`chart-period-${this.monitorId}`);
|
this.$root.storage().removeItem(`chart-period-${this.monitorId}`);
|
||||||
} else {
|
} else {
|
||||||
@@ -241,7 +242,11 @@ export default {
|
|||||||
// And mirror latest change to this.heartbeatList
|
// And mirror latest change to this.heartbeatList
|
||||||
this.$watch(() => this.$root.heartbeatList[this.monitorId],
|
this.$watch(() => this.$root.heartbeatList[this.monitorId],
|
||||||
(heartbeatList) => {
|
(heartbeatList) => {
|
||||||
if (this.chartPeriodHrs !== 0) {
|
|
||||||
|
log.debug("ping_chart", `this.chartPeriodHrs type ${typeof this.chartPeriodHrs}, value: ${this.chartPeriodHrs}`);
|
||||||
|
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
|
if (this.chartPeriodHrs != "0") {
|
||||||
const newBeat = heartbeatList.at(-1);
|
const newBeat = heartbeatList.at(-1);
|
||||||
if (newBeat && dayjs.utc(newBeat.time) > dayjs.utc(this.heartbeatList.at(-1)?.time)) {
|
if (newBeat && dayjs.utc(newBeat.time) > dayjs.utc(this.heartbeatList.at(-1)?.time)) {
|
||||||
this.heartbeatList.push(heartbeatList.at(-1));
|
this.heartbeatList.push(heartbeatList.at(-1));
|
||||||
|
@@ -33,19 +33,19 @@
|
|||||||
<template #item="monitor">
|
<template #item="monitor">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-9 col-md-8 small-padding">
|
<div class="col-9 col-md-8 small-padding d-flex align-items-center flex-wrap">
|
||||||
<div class="info">
|
<div class="info d-flex align-items-center gap-3 w-100">
|
||||||
<font-awesome-icon v-if="editMode" icon="arrows-alt-v" class="action drag me-3" />
|
<font-awesome-icon v-if="editMode" icon="arrows-alt-v" class="action drag me-3" />
|
||||||
<font-awesome-icon v-if="editMode" icon="times" class="action remove me-3" @click="removeMonitor(group.index, monitor.index)" />
|
<font-awesome-icon v-if="editMode" icon="times" class="action remove me-3" @click="removeMonitor(group.index, monitor.index)" />
|
||||||
|
|
||||||
<Uptime :monitor="monitor.element" type="24" :pill="true" />
|
<Uptime :monitor="monitor.element" type="24" :pill="true" />
|
||||||
{{ monitor.element.name }}
|
{{ monitor.element.name }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showTags" class="tags">
|
<div v-if="showTags && monitor.element.tags.length > 0" class="tags">
|
||||||
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
|
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :key="$root.userHeartbeatBar" class="col-3 col-md-4">
|
<div :key="$root.userHeartbeatBar" class="col-3 col-md-4 d-flex align-items-center">
|
||||||
<HeartbeatBar size="small" :monitor-id="monitor.element.id" />
|
<HeartbeatBar size="small" :monitor-id="monitor.element.id" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -5,7 +5,10 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
status: Number,
|
status: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
@@ -5,8 +5,14 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
monitor: Object,
|
monitor: {
|
||||||
type: String,
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
pill: {
|
pill: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@@ -8,6 +8,9 @@
|
|||||||
<a href="https://github.com/caronc/apprise/wiki#notification-services" target="_blank">https://github.com/caronc/apprise/wiki#notification-services</a>
|
<a href="https://github.com/caronc/apprise/wiki#notification-services" target="_blank">https://github.com/caronc/apprise/wiki#notification-services</a>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<label for="title" class="form-label">{{ $t("Title") }}</label>
|
||||||
|
<input id="title" v-model="$parent.notification.title" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<i18n-t tag="p" keypath="Status:">
|
<i18n-t tag="p" keypath="Status:">
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="clicksendsms-login" class="form-label">API Username</label>
|
<label for="clicksendsms-login" class="form-label">{{ $t("API Username") }}</label>
|
||||||
<div class="form-text">
|
<i18n-t tag="div" class="form-text" keypath="wayToGetClickSendSMSToken">
|
||||||
{{ $t("apiCredentials") }}
|
|
||||||
<a href="http://dashboard.clicksend.com/account/subaccounts" target="_blank">{{ $t("here") }}</a>
|
<a href="http://dashboard.clicksend.com/account/subaccounts" target="_blank">{{ $t("here") }}</a>
|
||||||
</div>
|
</i18n-t>
|
||||||
<input id="clicksendsms-login" v-model="$parent.notification.clicksendsmsLogin" type="text" class="form-control" required>
|
<input id="clicksendsms-login" v-model="$parent.notification.clicksendsmsLogin" type="text" class="form-control" required>
|
||||||
<label for="clicksendsms-key" class="form-label">API Key</label>
|
<label for="clicksendsms-key" class="form-label">{{ $t("API Key") }}</label>
|
||||||
<HiddenInput id="clicksendsms-key" v-model="$parent.notification.clicksendsmsPassword" :required="true" autocomplete="one-time-code"></HiddenInput>
|
<HiddenInput id="clicksendsms-key" v-model="$parent.notification.clicksendsmsPassword" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@@ -16,15 +15,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="clicksendsms-to-number" class="form-label">Recipient Number</label>
|
<label for="clicksendsms-to-number" class="form-label">{{ $t("Recipient Number") }}</label>
|
||||||
<input id="clicksendsms-to-number" v-model="$parent.notification.clicksendsmsToNumber" type="text" minlength="8" maxlength="14" class="form-control" required>
|
<input id="clicksendsms-to-number" v-model="$parent.notification.clicksendsmsToNumber" type="text" minlength="8" maxlength="14" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="clicksendsms-sender-name" class="form-label">From Name/Number -
|
<label for="clicksendsms-sender-name" class="form-label">{{ $t("From Name/Number") }} -
|
||||||
<a href="https://help.clicksend.com/article/4kgj7krx00-what-is-a-sender-id-or-sender-number" target="_blank">More Info</a>
|
<a href="https://help.clicksend.com/article/4kgj7krx00-what-is-a-sender-id-or-sender-number" target="_blank">{{ $t("Read more") }}</a>
|
||||||
</label>
|
</label>
|
||||||
<input id="clicksendsms-sender-name" v-model="$parent.notification.clicksendsmsSenderName" type="text" minlength="3" maxlength="11" class="form-control">
|
<input id="clicksendsms-sender-name" v-model="$parent.notification.clicksendsmsSenderName" type="text" minlength="3" maxlength="11" class="form-control">
|
||||||
<div class="form-text">Leave blank to use a shared sender number.</div>
|
<div class="form-text">{{ $t("Leave blank to use a shared sender number.") }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<b>{{ $t("Basic Settings") }}</b>
|
<b>{{ $t("Basic Settings") }}</b>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
<div class="mb-3" style="margin-top: 12px;">
|
<div class="mb-3" style="margin-top: 12px;">
|
||||||
<label for="line-user-id" class="form-label">User ID</label>
|
<label for="line-user-id" class="form-label">{{ $t("User ID") }}</label>
|
||||||
<input id="line-user-id" v-model="$parent.notification.lineUserID" type="text" class="form-control" required>
|
<input id="line-user-id" v-model="$parent.notification.lineUserID" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<i18n-t tag="div" keypath="lineDevConsoleTo" class="form-text">
|
<i18n-t tag="div" keypath="lineDevConsoleTo" class="form-text">
|
||||||
|
@@ -1,18 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="octopush-version" class="form-label">Octopush API Version</label>
|
<label for="octopush-version" class="form-label">{{ $t("Octopush API Version") }}</label>
|
||||||
<select id="octopush-version" v-model="$parent.notification.octopushVersion" class="form-select">
|
<select id="octopush-version" v-model="$parent.notification.octopushVersion" class="form-select">
|
||||||
<option value="2">Octopush (endpoint: api.octopush.com)</option>
|
<option value="2">{{ $t("octopush") }} ({{ $t("endpoint") }}: api.octopush.com)</option>
|
||||||
<option value="1">Legacy Octopush-DM (endpoint: www.octopush-dm.com)</option>
|
<option value="1">{{ $t("Legacy Octopush-DM") }} ({{ $t("endpoint") }}: www.octopush-dm.com)</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
{{ $t("octopushLegacyHint") }}
|
{{ $t("octopushLegacyHint") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="octopush-key" class="form-label">API KEY</label>
|
<label for="octopush-key" class="form-label">{{ $t("octopushAPIKey") }}</label>
|
||||||
<HiddenInput id="octopush-key" v-model="$parent.notification.octopushAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
<HiddenInput id="octopush-key" v-model="$parent.notification.octopushAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
<label for="octopush-login" class="form-label">API LOGIN</label>
|
<label for="octopush-login" class="form-label">{{ $t("octopushLogin") }}</label>
|
||||||
<input id="octopush-login" v-model="$parent.notification.octopushLogin" type="text" class="form-control" required>
|
<input id="octopush-login" v-model="$parent.notification.octopushLogin" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="promosms-login" class="form-label">API LOGIN</label>
|
<label for="promosms-login" class="form-label">{{ $("promosmsLogin") }}</label>
|
||||||
<input id="promosms-login" v-model="$parent.notification.promosmsLogin" type="text" class="form-control" required>
|
<input id="promosms-login" v-model="$parent.notification.promosmsLogin" type="text" class="form-control" required>
|
||||||
<label for="promosms-key" class="form-label">API PASSWORD</label>
|
<label for="promosms-key" class="form-label">{{ $("promosmsPassword") }}</label>
|
||||||
<HiddenInput id="promosms-key" v-model="$parent.notification.promosmsPassword" :required="true" autocomplete="one-time-code"></HiddenInput>
|
<HiddenInput id="promosms-key" v-model="$parent.notification.promosmsPassword" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@@ -18,28 +18,29 @@
|
|||||||
</select>
|
</select>
|
||||||
<label for="pushover-sound" class="form-label">{{ $t("Notification Sound") }}</label>
|
<label for="pushover-sound" class="form-label">{{ $t("Notification Sound") }}</label>
|
||||||
<select id="pushover-sound" v-model="$parent.notification.pushoversounds" class="form-select">
|
<select id="pushover-sound" v-model="$parent.notification.pushoversounds" class="form-select">
|
||||||
<option>pushover</option>
|
<option value="pushover">{{ $t("pushoversounds pushover") }}</option>
|
||||||
<option>bike</option>
|
<option value="bike">{{ $t("pushoversounds bike") }}</option>
|
||||||
<option>bugle</option>
|
<option value="bugle">{{ $t("pushoversounds bugle") }}</option>
|
||||||
<option>cashregister</option>
|
<option value="cashregister">{{ $t("pushoversounds cashregister") }}</option>
|
||||||
<option>classical</option>
|
<option value="classical">{{ $t("pushoversounds classical") }}</option>
|
||||||
<option>cosmic</option>
|
<option value="cosmic">{{ $t("pushoversounds cosmic") }}</option>
|
||||||
<option>falling</option>
|
<option value="falling">{{ $t("pushoversounds falling") }}</option>
|
||||||
<option>gamelan</option>
|
<option value="gamelan">{{ $t("pushoversounds gamelan") }}</option>
|
||||||
<option>incoming</option>
|
<option value="incoming">{{ $t("pushoversounds incoming") }}</option>
|
||||||
<option>intermission</option>
|
<option value="intermission">{{ $t("pushoversounds intermission") }}</option>
|
||||||
<option>mechanical</option>
|
<option value="magic">{{ $t("pushoversounds magic") }}</option>
|
||||||
<option>pianobar</option>
|
<option value="mechanical">{{ $t("pushoversounds mechanical") }}</option>
|
||||||
<option>siren</option>
|
<option value="pianobar">{{ $t("pushoversounds pianobar") }}</option>
|
||||||
<option>spacealarm</option>
|
<option value="siren">{{ $t("pushoversounds siren") }}</option>
|
||||||
<option>tugboat</option>
|
<option value="spacealarm">{{ $t("pushoversounds spacealarm") }}</option>
|
||||||
<option>alien</option>
|
<option value="tugboat">{{ $t("pushoversounds tugboat") }}</option>
|
||||||
<option>climb</option>
|
<option value="alien">{{ $t("pushoversounds alien") }}</option>
|
||||||
<option>persistent</option>
|
<option value="climb">{{ $t("pushoversounds climb") }}</option>
|
||||||
<option>echo</option>
|
<option value="persistent">{{ $t("pushoversounds persistent") }}</option>
|
||||||
<option>updown</option>
|
<option value="echo">{{ $t("pushoversounds echo") }}</option>
|
||||||
<option>vibrate</option>
|
<option value="updown">{{ $t("pushoversounds updown") }}</option>
|
||||||
<option>none</option>
|
<option value="vibrate">{{ $t("pushoversounds vibrate") }}</option>
|
||||||
|
<option value="none">{{ $t("pushoversounds none") }}</option>
|
||||||
</select>
|
</select>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pushy-app-token" class="form-label">API_KEY</label>
|
<label for="pushy-app-token" class="form-label">{{ $t("pushyAPIKey") }}</label>
|
||||||
<HiddenInput id="pushy-app-token" v-model="$parent.notification.pushyAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
<HiddenInput id="pushy-app-token" v-model="$parent.notification.pushyAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pushy-user-key" class="form-label">USER_TOKEN</label>
|
<label for="pushy-user-key" class="form-label">{{ $t("pushyToken") }}</label>
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<HiddenInput id="pushy-user-key" v-model="$parent.notification.pushyToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
<HiddenInput id="pushy-user-key" v-model="$parent.notification.pushyToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="push-api-key" class="form-label">API_KEY</label>
|
<label for="push-api-key" class="form-label">{{ $t("API Key") }}</label>
|
||||||
<HiddenInput id="push-api-key" v-model="$parent.notification.pushAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
<HiddenInput id="push-api-key" v-model="$parent.notification.pushAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<label><input v-model="settings.checkUpdate" type="checkbox" @change="saveSettings()" /> Show update if available</label>
|
<label><input v-model="settings.checkUpdate" type="checkbox" @change="saveSettings()" /> {{ $t("Show update if available") }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<label><input v-model="settings.checkBeta" type="checkbox" :disabled="!settings.checkUpdate" @change="saveSettings()" /> Also check beta release</label>
|
<label><input v-model="settings.checkBeta" type="checkbox" :disabled="!settings.checkUpdate" @change="saveSettings()" /> {{ $t("Also check beta release") }}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -12,15 +12,15 @@ export default {
|
|||||||
keywordDescription: "Търси ключова дума в чист html или JSON отговор - чувствителна е към регистъра",
|
keywordDescription: "Търси ключова дума в чист html или JSON отговор - чувствителна е към регистъра",
|
||||||
pauseDashboardHome: "Пауза",
|
pauseDashboardHome: "Пауза",
|
||||||
deleteMonitorMsg: "Наистина ли желаете да изтриете този монитор?",
|
deleteMonitorMsg: "Наистина ли желаете да изтриете този монитор?",
|
||||||
deleteNotificationMsg: "Наистина ли желаете да изтриете това известяване за всички монитори?",
|
deleteNotificationMsg: "Наистина ли желаете да изтриете това известие за всички монитори?",
|
||||||
resolverserverDescription: "Cloudflare е сървърът по подразбиране, но можете да го промените по всяко време.",
|
resolverserverDescription: "Cloudflare е сървърът по подразбиране, но можете да го промените по всяко време.",
|
||||||
rrtypeDescription: "Изберете ресурсния запис, който желаете да наблюдавате",
|
rrtypeDescription: "Изберете ресурсния запис, който желаете да наблюдавате",
|
||||||
pauseMonitorMsg: "Наистина ли желаете да поставите в режим пауза?",
|
pauseMonitorMsg: "Наистина ли желаете да поставите в режим пауза?",
|
||||||
enableDefaultNotificationDescription: "За всеки нов монитор това известяване ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.",
|
enableDefaultNotificationDescription: "За всеки нов монитор това известие ще бъде активирано по подразбиране. Можете да го изключите за всеки отделен монитор.",
|
||||||
clearEventsMsg: "Наистина ли желаете да изтриете всички събития за този монитор?",
|
clearEventsMsg: "Наистина ли желаете да изтриете всички събития за този монитор?",
|
||||||
clearHeartbeatsMsg: "Наистина ли желаете да изтриете всички записи за честотни проверки на този монитор?",
|
clearHeartbeatsMsg: "Наистина ли желаете да изтриете всички записи за честотни проверки на този монитор?",
|
||||||
confirmClearStatisticsMsg: "Наистина ли желаете да изтриете всички статистически данни?",
|
confirmClearStatisticsMsg: "Наистина ли желаете да изтриете всички статистически данни?",
|
||||||
importHandleDescription: "Изберете 'Пропусни съществуващите', ако желаете да пропуснете всеки монитор или известяване със същото име. 'Презапис' ще изтрие всеки съществуващ монитор и известяване.",
|
importHandleDescription: "Изберете 'Пропусни съществуващите', ако желаете да пропуснете всеки монитор или известие със същото име. 'Презапис' ще изтрие всеки съществуващ монитор и известие.",
|
||||||
confirmImportMsg: "Сигурни ли сте, че желаете импортирането на архива? Моля, уверете се, че сте избрали правилната опция за импортиране.",
|
confirmImportMsg: "Сигурни ли сте, че желаете импортирането на архива? Моля, уверете се, че сте избрали правилната опция за импортиране.",
|
||||||
twoFAVerifyLabel: "Моля, въведете вашия токен код, за да проверите дали 2FA работи",
|
twoFAVerifyLabel: "Моля, въведете вашия токен код, за да проверите дали 2FA работи",
|
||||||
tokenValidSettingsMsg: "Токен кодът е валиден! Вече можете да запазите настройките за 2FA.",
|
tokenValidSettingsMsg: "Токен кодът е валиден! Вече можете да запазите настройките за 2FA.",
|
||||||
@@ -76,9 +76,9 @@ export default {
|
|||||||
"Max. Redirects": "Макс. брой пренасочвания",
|
"Max. Redirects": "Макс. брой пренасочвания",
|
||||||
"Accepted Status Codes": "Допустими статус кодове",
|
"Accepted Status Codes": "Допустими статус кодове",
|
||||||
Save: "Запази",
|
Save: "Запази",
|
||||||
Notifications: "Известявания",
|
Notifications: "Известия",
|
||||||
"Not available, please setup.": "Не са налични. Моля, настройте.",
|
"Not available, please setup.": "Не са налични. Моля, настройте.",
|
||||||
"Setup Notification": "Настрой известяване",
|
"Setup Notification": "Настрой известие",
|
||||||
Light: "Светла",
|
Light: "Светла",
|
||||||
Dark: "Тъмна",
|
Dark: "Тъмна",
|
||||||
Auto: "Автоматично",
|
Auto: "Автоматично",
|
||||||
@@ -109,7 +109,7 @@ export default {
|
|||||||
Login: "Вход",
|
Login: "Вход",
|
||||||
"No Monitors, please": "Все още няма монитори. Моля, добавете поне ",
|
"No Monitors, please": "Все още няма монитори. Моля, добавете поне ",
|
||||||
"add one": "един.",
|
"add one": "един.",
|
||||||
"Notification Type": "Тип известяване",
|
"Notification Type": "Тип известие",
|
||||||
Email: "Имейл",
|
Email: "Имейл",
|
||||||
Test: "Тест",
|
Test: "Тест",
|
||||||
"Certificate Info": "Информация за сертификат",
|
"Certificate Info": "Информация за сертификат",
|
||||||
@@ -131,9 +131,9 @@ export default {
|
|||||||
Events: "Събития",
|
Events: "Събития",
|
||||||
Heartbeats: "Проверки",
|
Heartbeats: "Проверки",
|
||||||
"Auto Get": "Авт. попълване",
|
"Auto Get": "Авт. попълване",
|
||||||
backupDescription: "Можете да архивирате всички монитори и всички известявания в JSON файл.",
|
backupDescription: "Можете да архивирате всички монитори и всички известия в JSON файл.",
|
||||||
backupDescription2: "PS: Имайте предвид, че данните за история и събития няма да бъдат включени.",
|
backupDescription2: "PS: Имайте предвид, че данните за история и събития няма да бъдат включени.",
|
||||||
backupDescription3: "Чувствителни данни, като токен кодове за известяване, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.",
|
backupDescription3: "Чувствителни данни, като токен кодове за известия, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.",
|
||||||
alertNoFile: "Моля, изберете файл за импортиране.",
|
alertNoFile: "Моля, изберете файл за импортиране.",
|
||||||
alertWrongFileType: "Моля, изберете JSON файл.",
|
alertWrongFileType: "Моля, изберете JSON файл.",
|
||||||
"Clear all statistics": "Изтрий цялата статистика",
|
"Clear all statistics": "Изтрий цялата статистика",
|
||||||
@@ -202,7 +202,7 @@ export default {
|
|||||||
"Push URL": "Генериран Push URL адрес",
|
"Push URL": "Генериран Push URL адрес",
|
||||||
needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди",
|
needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди",
|
||||||
pushOptionalParams: "Допълнителни, но не задължителни параметри: {0}",
|
pushOptionalParams: "Допълнителни, но не задължителни параметри: {0}",
|
||||||
defaultNotificationName: "Моето {notification} известяване ({number})",
|
defaultNotificationName: "Моето {notification} известие ({number})",
|
||||||
here: "тук",
|
here: "тук",
|
||||||
Required: "Задължително поле",
|
Required: "Задължително поле",
|
||||||
"Bot Token": "Бот токен",
|
"Bot Token": "Бот токен",
|
||||||
@@ -252,7 +252,7 @@ export default {
|
|||||||
"Notification Sound": "Звуков сигнал",
|
"Notification Sound": "Звуков сигнал",
|
||||||
"More info on:": "Повече информация на: {0}",
|
"More info on:": "Повече информация на: {0}",
|
||||||
pushoverDesc1: "Приоритет Спешно (2) по подразбиране изчаква 30 секунди между повторните опити и изтича след 1 час.",
|
pushoverDesc1: "Приоритет Спешно (2) по подразбиране изчаква 30 секунди между повторните опити и изтича след 1 час.",
|
||||||
pushoverDesc2: "Ако желаете да изпратите известявания до различни устройства, попълнете полето Устройство.",
|
pushoverDesc2: "Ако желаете да изпратите известия до различни устройства, попълнете полето Устройство.",
|
||||||
"SMS Type": "SMS тип",
|
"SMS Type": "SMS тип",
|
||||||
octopushTypePremium: "Премиум (Бърз - препоръчителен в случай на тревога)",
|
octopushTypePremium: "Премиум (Бърз - препоръчителен в случай на тревога)",
|
||||||
octopushTypeLowCost: "Евтин (Бавен - понякога бива блокиран от оператора)",
|
octopushTypeLowCost: "Евтин (Бавен - понякога бива блокиран от оператора)",
|
||||||
@@ -275,7 +275,7 @@ export default {
|
|||||||
lineDevConsoleTo: "Line - Конзола за разработчици - {0}",
|
lineDevConsoleTo: "Line - Конзола за разработчици - {0}",
|
||||||
"Basic Settings": "Основни настройки",
|
"Basic Settings": "Основни настройки",
|
||||||
"User ID": "Потребител ID",
|
"User ID": "Потребител ID",
|
||||||
"Messaging API": "API за известяване",
|
"Messaging API": "API за съобщаване",
|
||||||
wayToGetLineChannelToken: "Необходимо е първо да посетите {0}, за да създадете (Messaging API) за доставчик и канал, след което може да вземете токен кода за канал и потребителско ID от споменатите по-горе елементи на менюто.",
|
wayToGetLineChannelToken: "Необходимо е първо да посетите {0}, за да създадете (Messaging API) за доставчик и канал, след което може да вземете токен кода за канал и потребителско ID от споменатите по-горе елементи на менюто.",
|
||||||
"Icon URL": "URL адрес за иконка",
|
"Icon URL": "URL адрес за иконка",
|
||||||
aboutIconURL: "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.",
|
aboutIconURL: "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.",
|
||||||
@@ -291,7 +291,7 @@ export default {
|
|||||||
matrixHomeserverURL: "Сървър URL адрес (започва с http(s):// и порт по желание)",
|
matrixHomeserverURL: "Сървър URL адрес (започва с http(s):// и порт по желание)",
|
||||||
"Internal Room Id": "ID на вътрешна стая",
|
"Internal Room Id": "ID на вътрешна стая",
|
||||||
matrixDesc1: "Може да намерите \"ID на вътрешна стая\" в разширените настройки на стаята във вашия Matrix клиент. Примерен изглед: !QMdRCpUIfLwsfjxye6:home.server.",
|
matrixDesc1: "Може да намерите \"ID на вътрешна стая\" в разширените настройки на стаята във вашия Matrix клиент. Примерен изглед: !QMdRCpUIfLwsfjxye6:home.server.",
|
||||||
matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребирел, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известяванията. Токен код за достъп ще получите изпълнявайки {0}",
|
matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребирел, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известията. Токен код за достъп ще получите изпълнявайки {0}",
|
||||||
Method: "Метод",
|
Method: "Метод",
|
||||||
Body: "Съобщение",
|
Body: "Съобщение",
|
||||||
Headers: "Хедъри",
|
Headers: "Хедъри",
|
||||||
@@ -449,7 +449,7 @@ export default {
|
|||||||
Customize: "Персонализирай",
|
Customize: "Персонализирай",
|
||||||
"Custom Footer": "Персонализиран долен колонтитул",
|
"Custom Footer": "Персонализиран долен колонтитул",
|
||||||
"Custom CSS": "Потребителски CSS",
|
"Custom CSS": "Потребителски CSS",
|
||||||
"Domain Name Expiry Notification": "Известяване при изтичащ домейн",
|
"Domain Name Expiry Notification": "Известие при изтичащ домейн",
|
||||||
Proxy: "Прокси",
|
Proxy: "Прокси",
|
||||||
"Date Created": "Дата на създаване",
|
"Date Created": "Дата на създаване",
|
||||||
onebotHttpAddress: "OneBot HTTP адрес",
|
onebotHttpAddress: "OneBot HTTP адрес",
|
||||||
|
@@ -464,4 +464,55 @@ export default {
|
|||||||
"Domain Names": "Domain Names",
|
"Domain Names": "Domain Names",
|
||||||
signedInDisp: "Signed in as {0}",
|
signedInDisp: "Signed in as {0}",
|
||||||
signedInDispDisabled: "Auth Disabled.",
|
signedInDispDisabled: "Auth Disabled.",
|
||||||
|
"Certificate Expiry Notification": "Certificate Expiry Notification",
|
||||||
|
"API Username": "API Username",
|
||||||
|
"API Key": "API Key",
|
||||||
|
"Recipient Number": "Recipient Number",
|
||||||
|
"From Name/Number": "From Name/Number",
|
||||||
|
"Leave blank to use a shared sender number.": "Leave blank to use a shared sender number.",
|
||||||
|
"Octopush API Version": "Octopush API Version",
|
||||||
|
"Legacy Octopush-DM": "Legacy Octopush-DM",
|
||||||
|
"endpoint": "endpoint",
|
||||||
|
octopushAPIKey: "\"API key\" from HTTP API credentials in control panel",
|
||||||
|
octopushLogin: "\"Login\" from HTTP API credentials in control panel",
|
||||||
|
promosmsLogin: "API Login Name",
|
||||||
|
promosmsPassword: "API Password",
|
||||||
|
"pushoversounds pushover": "Pushover (default)",
|
||||||
|
"pushoversounds bike": "Bike",
|
||||||
|
"pushoversounds bugle": "Bugle",
|
||||||
|
"pushoversounds cashregister": "Cash Register",
|
||||||
|
"pushoversounds classical": "Classical",
|
||||||
|
"pushoversounds cosmic": "Cosmic",
|
||||||
|
"pushoversounds falling": "Falling",
|
||||||
|
"pushoversounds gamelan": "Gamelan",
|
||||||
|
"pushoversounds incoming": "Incoming",
|
||||||
|
"pushoversounds intermission": "Intermission",
|
||||||
|
"pushoversounds magic": "Magic",
|
||||||
|
"pushoversounds mechanical": "Mechanical",
|
||||||
|
"pushoversounds pianobar": "Piano Bar",
|
||||||
|
"pushoversounds siren": "Siren",
|
||||||
|
"pushoversounds spacealarm": "Space Alarm",
|
||||||
|
"pushoversounds tugboat": "Tug Boat",
|
||||||
|
"pushoversounds alien": "Alien Alarm (long)",
|
||||||
|
"pushoversounds climb": "Climb (long)",
|
||||||
|
"pushoversounds persistent": "Persistent (long)",
|
||||||
|
"pushoversounds echo": "Pushover Echo (long)",
|
||||||
|
"pushoversounds updown": "Up Down (long)",
|
||||||
|
"pushoversounds vibrate": "Vibrate Only",
|
||||||
|
"pushoversounds none": "None (silent)",
|
||||||
|
pushyAPIKey: "Secret API Key",
|
||||||
|
pushyToken: "Device token",
|
||||||
|
"Show update if available": "Show update if available",
|
||||||
|
"Also check beta release": "Also check beta release",
|
||||||
|
"Using a Reverse Proxy?": "Using a Reverse Proxy?",
|
||||||
|
"Check how to config it for WebSocket": "Check how to config it for WebSocket",
|
||||||
|
"Steam Game Server": "Steam Game Server",
|
||||||
|
"Most likely causes:": "Most likely causes:",
|
||||||
|
"The resource is no longer available.": "The resource is no longer available.",
|
||||||
|
"There might be a typing error in the address.": "There might be a typing error in the address.",
|
||||||
|
"What you can try:": "What you can try:",
|
||||||
|
"Retype the address.": "Retype the address.",
|
||||||
|
"Go back to the previous page.": "Go back to the previous page.",
|
||||||
|
"Coming Soon": "Coming Soon",
|
||||||
|
wayToGetClickSendSMSToken: "You can get API Username and API Key from {0} .",
|
||||||
};
|
};
|
||||||
|
@@ -88,7 +88,7 @@ export default {
|
|||||||
Dark: "黑暗",
|
Dark: "黑暗",
|
||||||
Auto: "自动",
|
Auto: "自动",
|
||||||
"Theme - Heartbeat Bar": "主题 - 心跳栏",
|
"Theme - Heartbeat Bar": "主题 - 心跳栏",
|
||||||
Normal: "正常", // 此处还供 Gorush 的通知优先级功能使用,不应翻译为“正常显示”
|
Normal: "正常",
|
||||||
Bottom: "靠下",
|
Bottom: "靠下",
|
||||||
None: "不显示",
|
None: "不显示",
|
||||||
Timezone: "时区",
|
Timezone: "时区",
|
||||||
@@ -398,11 +398,9 @@ export default {
|
|||||||
Invalid: "无效",
|
Invalid: "无效",
|
||||||
AccessKeyId: "AccessKey ID",
|
AccessKeyId: "AccessKey ID",
|
||||||
SecretAccessKey: "AccessKey Secret",
|
SecretAccessKey: "AccessKey Secret",
|
||||||
/* 以下为阿里云短信服务 API Dysms#SendSms 的参数 */
|
|
||||||
PhoneNumbers: "PhoneNumbers",
|
PhoneNumbers: "PhoneNumbers",
|
||||||
TemplateCode: "TemplateCode",
|
TemplateCode: "TemplateCode",
|
||||||
SignName: "SignName",
|
SignName: "SignName",
|
||||||
/* 以上为阿里云短信服务 API Dysms#SendSms 的参数 */
|
|
||||||
"Bark Endpoint": "Bark 接入点",
|
"Bark Endpoint": "Bark 接入点",
|
||||||
"Device Token": "Apple Device Token",
|
"Device Token": "Apple Device Token",
|
||||||
Platform: "平台",
|
Platform: "平台",
|
||||||
@@ -441,7 +439,7 @@ export default {
|
|||||||
"No Proxy": "无代理",
|
"No Proxy": "无代理",
|
||||||
"HTTP Basic Auth": "HTTP 基础身份验证",
|
"HTTP Basic Auth": "HTTP 基础身份验证",
|
||||||
"New Status Page": "新的状态页",
|
"New Status Page": "新的状态页",
|
||||||
"Page Not Found": "状态页未找到",
|
"Page Not Found": "未找到该页面",
|
||||||
"Reverse Proxy": "反向代理",
|
"Reverse Proxy": "反向代理",
|
||||||
"Subject:": "颁发给:",
|
"Subject:": "颁发给:",
|
||||||
"Valid To:": "有效期至:",
|
"Valid To:": "有效期至:",
|
||||||
@@ -469,4 +467,57 @@ export default {
|
|||||||
"Footer Text": "底部自定义文本",
|
"Footer Text": "底部自定义文本",
|
||||||
"Show Powered By": "显示 Powered By",
|
"Show Powered By": "显示 Powered By",
|
||||||
"Domain Names": "域名",
|
"Domain Names": "域名",
|
||||||
|
"Certificate Expiry Notification": "证书到期时通知",
|
||||||
|
"API Username": "API 凭证 Username",
|
||||||
|
"API Key": "API 凭证 Key",
|
||||||
|
"Recipient Number": "收件人手机号码",
|
||||||
|
"From Name/Number": "发件人名称/手机号码",
|
||||||
|
"Leave blank to use a shared sender number.": "留空以使用平台共享的发件人手机号码",
|
||||||
|
"Octopush API Version": "Octopush API 版本",
|
||||||
|
"Legacy Octopush-DM": "旧版本 Octopush-DM",
|
||||||
|
endpoint: "接入点",
|
||||||
|
octopushAPIKey: "控制台 HTTP API credentials 里的 \"API key\"",
|
||||||
|
octopushLogin: "控制台 HTTP API credentials 里的 \"Login\"",
|
||||||
|
promosmsLogin: "API 登录名",
|
||||||
|
promosmsPassword: "API 密码",
|
||||||
|
"pushoversounds pushover": "Pushover(默认)",
|
||||||
|
"pushoversounds bike": "Bike",
|
||||||
|
"pushoversounds bugle": "Bugle",
|
||||||
|
"pushoversounds cashregister": "Cash Register",
|
||||||
|
"pushoversounds classical": "Classical",
|
||||||
|
"pushoversounds cosmic": "Cosmic",
|
||||||
|
"pushoversounds falling": "Falling",
|
||||||
|
"pushoversounds gamelan": "Gamelan",
|
||||||
|
"pushoversounds incoming": "Incoming",
|
||||||
|
"pushoversounds intermission": "Intermission",
|
||||||
|
"pushoversounds magic": "Magic",
|
||||||
|
"pushoversounds mechanical": "Mechanical",
|
||||||
|
"pushoversounds pianobar": "Piano Bar",
|
||||||
|
"pushoversounds siren": "Siren",
|
||||||
|
"pushoversounds spacealarm": "Space Alarm",
|
||||||
|
"pushoversounds tugboat": "Tug Boat",
|
||||||
|
"pushoversounds alien": "Alien Alarm(长铃声)",
|
||||||
|
"pushoversounds climb": "Climb(长铃声)",
|
||||||
|
"pushoversounds persistent": "Persistent(长铃声)",
|
||||||
|
"pushoversounds echo": "Pushover Echo(长铃声)",
|
||||||
|
"pushoversounds updown": "Up Down(长铃声)",
|
||||||
|
"pushoversounds vibrate": "仅震动",
|
||||||
|
"pushoversounds none": "无(禁音)",
|
||||||
|
pushyAPIKey: "API 密钥",
|
||||||
|
pushyToken: "设备 Token",
|
||||||
|
"Show update if available": "有更新时通知",
|
||||||
|
"Also check beta release": "一并检查 Beta 版更新",
|
||||||
|
"Using a Reverse Proxy?": "正在使用反向代理?",
|
||||||
|
"Check how to config it for WebSocket": "查看如何将反向代理与 WebSocket 一起使用",
|
||||||
|
"Steam Game Server": "Steam 游戏服务器",
|
||||||
|
"Most likely causes:": "最可能的原因:",
|
||||||
|
"The resource is no longer available.": "您所请求的资源已不再可用;",
|
||||||
|
"There might be a typing error in the address.": "您输入的地址可能有误。",
|
||||||
|
"What you can try:": "您可以尝试以下操作:",
|
||||||
|
"Retype the address.": "重新输入地址;",
|
||||||
|
"Go back to the previous page.": "返回到上一页面。",
|
||||||
|
"Coming Soon": "即将推出",
|
||||||
|
wayToGetClickSendSMSToken: "您可以从 {0} 获取 API 凭证 Username 和 凭证 Key。",
|
||||||
|
signedInDisp: "当前用户: {0}",
|
||||||
|
signedInDispDisabled: "已禁用身份验证",
|
||||||
};
|
};
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
{{ $root.connectionErrorMsg }}
|
{{ $root.connectionErrorMsg }}
|
||||||
<div v-if="$root.showReverseProxyGuide">
|
<div v-if="$root.showReverseProxyGuide">
|
||||||
Using a Reverse Proxy? <a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">Check how to config it for WebSocket</a>
|
{{ $t("Using a Reverse Proxy?") }} <a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">{{ $t("Check how to config it for WebSocket") }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li v-if="$root.loggedIn" class="nav-item">
|
<li v-if="$root.loggedIn" class="nav-item">
|
||||||
<div class="dropdown dropdown-profile-pic">
|
<div class="dropdown dropdown-profile-pic">
|
||||||
<div type="button" class="nav-link" data-bs-toggle="dropdown">
|
<div class="nav-link" data-bs-toggle="dropdown">
|
||||||
<div class="profile-pic">{{ $root.usernameFirstChar }}</div>
|
<div class="profile-pic">{{ $root.usernameFirstChar }}</div>
|
||||||
<font-awesome-icon icon="angle-down" />
|
<font-awesome-icon icon="angle-down" />
|
||||||
</div>
|
</div>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<router-view v-if="$root.loggedIn || forceShowContent" />
|
<router-view v-if="$root.loggedIn" />
|
||||||
<Login v-if="! $root.loggedIn && $root.allowLoginDialog" />
|
<Login v-if="! $root.loggedIn && $root.allowLoginDialog" />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
Push
|
Push
|
||||||
</option>
|
</option>
|
||||||
<option value="steam">
|
<option value="steam">
|
||||||
Steam Game Server
|
{{ $t("Steam Game Server") }}
|
||||||
</option>
|
</option>
|
||||||
<option value="mqtt">
|
<option value="mqtt">
|
||||||
MQTT
|
MQTT
|
||||||
@@ -421,7 +421,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
pushURL() {
|
pushURL() {
|
||||||
return this.$root.baseURL + "/api/push/" + this.monitor.pushToken + "?status=true&msg=OK&ping=";
|
return this.$root.baseURL + "/api/push/" + this.monitor.pushToken + "?status=up&msg=OK&ping=";
|
||||||
},
|
},
|
||||||
|
|
||||||
bodyPlaceholder() {
|
bodyPlaceholder() {
|
||||||
|
@@ -22,16 +22,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="guide">
|
<div class="guide">
|
||||||
Most likely causes:
|
{{ $t("Most likely causes:") }}
|
||||||
<ul>
|
<ul>
|
||||||
<li>The resource is no longer available.</li>
|
<li>{{ $t("The resource is no longer available.") }}</li>
|
||||||
<li>There might be a typing error in the address.</li>
|
<li>{{ $t("There might be a typing error in the address.") }}</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
What you can try:<br />
|
{{ $t("What you can try:") }}<br />
|
||||||
<ul>
|
<ul>
|
||||||
<li>Retype the address.</li>
|
<li>{{ $t("Retype the address.") }}</li>
|
||||||
<li><a href="#" class="go-back" @click="goBack()">Go back to the previous page.</a></li>
|
<li><a href="#" class="go-back" @click="goBack()">{{ $t("Go back to the previous page.") }}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -45,7 +45,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="false" class="my-3">
|
<div v-if="false" class="my-3">
|
||||||
<label for="password" class="form-label">{{ $t("Password") }} <sup>Coming Soon</sup></label>
|
<label for="password" class="form-label">{{ $t("Password") }} <sup>{{ $t("Coming Soon") }}</sup></label>
|
||||||
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
|
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -104,15 +104,16 @@
|
|||||||
|
|
||||||
<!-- Uploader -->
|
<!-- Uploader -->
|
||||||
<!-- url="/api/status-page/upload-logo" -->
|
<!-- url="/api/status-page/upload-logo" -->
|
||||||
<ImageCropUpload v-model="showImageCropUpload"
|
<ImageCropUpload
|
||||||
field="img"
|
v-model="showImageCropUpload"
|
||||||
:width="128"
|
field="img"
|
||||||
:height="128"
|
:width="128"
|
||||||
:langType="$i18n.locale"
|
:height="128"
|
||||||
img-format="png"
|
:langType="$i18n.locale"
|
||||||
:noCircle="true"
|
img-format="png"
|
||||||
:noSquare="false"
|
:noCircle="true"
|
||||||
@crop-success="cropSuccess"
|
:noSquare="false"
|
||||||
|
@crop-success="cropSuccess"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
@@ -281,22 +282,21 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import PublicGroupList from "../components/PublicGroupList.vue";
|
|
||||||
import ImageCropUpload from "vue-image-crop-upload";
|
|
||||||
import { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_PARTIAL_DOWN, UP } from "../util.ts";
|
|
||||||
import { useToast } from "vue-toastification";
|
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import Favico from "favico.js";
|
import Favico from "favico.js";
|
||||||
import { getResBaseURL } from "../util-frontend";
|
|
||||||
import Confirm from "../components/Confirm.vue";
|
|
||||||
// import Prism Editor
|
|
||||||
import { PrismEditor } from "vue-prism-editor";
|
|
||||||
import "vue-prism-editor/dist/prismeditor.min.css"; // import the styles somewhere
|
|
||||||
|
|
||||||
// import highlighting library (you can use any library you want just return html string)
|
// import highlighting library (you can use any library you want just return html string)
|
||||||
import { highlight, languages } from "prismjs/components/prism-core";
|
import { highlight, languages } from "prismjs/components/prism-core";
|
||||||
import "prismjs/components/prism-css";
|
import "prismjs/components/prism-css";
|
||||||
import "prismjs/themes/prism-tomorrow.css"; // import syntax highlighting styles
|
import "prismjs/themes/prism-tomorrow.css"; // import syntax highlighting styles
|
||||||
|
import ImageCropUpload from "vue-image-crop-upload";
|
||||||
|
// import Prism Editor
|
||||||
|
import { PrismEditor } from "vue-prism-editor";
|
||||||
|
import "vue-prism-editor/dist/prismeditor.min.css"; // import the styles somewhere
|
||||||
|
import { useToast } from "vue-toastification";
|
||||||
|
import Confirm from "../components/Confirm.vue";
|
||||||
|
import PublicGroupList from "../components/PublicGroupList.vue";
|
||||||
|
import { getResBaseURL } from "../util-frontend";
|
||||||
|
import { STATUS_PAGE_ALL_DOWN, STATUS_PAGE_ALL_UP, STATUS_PAGE_PARTIAL_DOWN, UP } from "../util.ts";
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
|
@@ -102,7 +102,7 @@ class Logger {
|
|||||||
}
|
}
|
||||||
else if (level === "DEBUG") {
|
else if (level === "DEBUG") {
|
||||||
if (exports.isDev) {
|
if (exports.isDev) {
|
||||||
console.debug(formattedMessage);
|
console.log(formattedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -113,7 +113,7 @@ class Logger {
|
|||||||
console.error(formattedMessage);
|
console.error(formattedMessage);
|
||||||
} else if (level === "DEBUG") {
|
} else if (level === "DEBUG") {
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
console.debug(formattedMessage);
|
console.log(formattedMessage);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(formattedMessage);
|
console.log(formattedMessage);
|
||||||
|
@@ -1,5 +1,9 @@
|
|||||||
const { genSecret } = require("../src/util");
|
const { genSecret, DOWN } = require("../src/util");
|
||||||
const utilServerRewire = require("../server/util-server");
|
const utilServerRewire = require("../server/util-server");
|
||||||
|
const Discord = require("../server/notification-providers/discord");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
jest.mock("axios");
|
||||||
|
|
||||||
describe("Test parseCertificateInfo", () => {
|
describe("Test parseCertificateInfo", () => {
|
||||||
it("should handle undefined", async () => {
|
it("should handle undefined", async () => {
|
||||||
@@ -164,3 +168,86 @@ describe("Test reset-password", () => {
|
|||||||
}, 120000);
|
}, 120000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Test Discord Notification Provider", () => {
|
||||||
|
const sendNotification = async (hostname, port, type) => {
|
||||||
|
const discordProvider = new Discord();
|
||||||
|
|
||||||
|
axios.post.mockResolvedValue({});
|
||||||
|
|
||||||
|
await discordProvider.send(
|
||||||
|
{
|
||||||
|
discordUsername: "Uptime Kuma",
|
||||||
|
discordWebhookUrl: "https://discord.com",
|
||||||
|
},
|
||||||
|
"test message",
|
||||||
|
{
|
||||||
|
type,
|
||||||
|
hostname,
|
||||||
|
port,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: DOWN,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
it("should send hostname for dns monitors", async () => {
|
||||||
|
const hostname = "discord.com";
|
||||||
|
await sendNotification(hostname, null, "dns");
|
||||||
|
|
||||||
|
expect(axios.post.mock.lastCall[1].embeds[0].fields[1].value).toBe(
|
||||||
|
hostname
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should send hostname for ping monitors", async () => {
|
||||||
|
const hostname = "discord.com";
|
||||||
|
await sendNotification(hostname, null, "ping");
|
||||||
|
|
||||||
|
expect(axios.post.mock.lastCall[1].embeds[0].fields[1].value).toBe(
|
||||||
|
hostname
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should send hostname for port monitors", async () => {
|
||||||
|
const hostname = "discord.com";
|
||||||
|
const port = 1337;
|
||||||
|
await sendNotification(hostname, port, "port");
|
||||||
|
|
||||||
|
expect(axios.post.mock.lastCall[1].embeds[0].fields[1].value).toBe(
|
||||||
|
`${hostname}:${port}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should send hostname for steam monitors", async () => {
|
||||||
|
const hostname = "discord.com";
|
||||||
|
const port = 1337;
|
||||||
|
await sendNotification(hostname, port, "steam");
|
||||||
|
|
||||||
|
expect(axios.post.mock.lastCall[1].embeds[0].fields[1].value).toBe(
|
||||||
|
`${hostname}:${port}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("The function filterAndJoin", () => {
|
||||||
|
it("should join and array of strings to one string", () => {
|
||||||
|
const result = utilServerRewire.filterAndJoin(["one", "two", "three"]);
|
||||||
|
expect(result).toBe("onetwothree");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should join strings using a given connector", () => {
|
||||||
|
const result = utilServerRewire.filterAndJoin(["one", "two", "three"], "-");
|
||||||
|
expect(result).toBe("one-two-three");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should filter null, undefined and empty strings before joining", () => {
|
||||||
|
const result = utilServerRewire.filterAndJoin([undefined, "", "three"], "--");
|
||||||
|
expect(result).toBe("three");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return an empty string if all parts are filtered out", () => {
|
||||||
|
const result = utilServerRewire.filterAndJoin([undefined, "", ""], "--");
|
||||||
|
expect(result).toBe("");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Reference in New Issue
Block a user