Compare commits

...

62 Commits
1.1.0 ... 1.2.0

Author SHA1 Message Date
LouisLam
5d0b6190c3 update to 1.2.0 2021-08-16 20:40:28 +08:00
LouisLam
cb85905c33 minor 2021-08-16 20:40:16 +08:00
LouisLam
981ed5f29f Merge remote-tracking branch 'origin/master' 2021-08-16 01:42:54 +08:00
LouisLam
0b45694f2f update all dependencies 2021-08-16 01:42:39 +08:00
Louis Lam
60531d0b15 Update README.md 2021-08-16 01:38:37 +08:00
Louis Lam
a3de63ac3c Update README.md 2021-08-16 01:29:47 +08:00
Louis Lam
80eadcb236 Merge pull request #214 from ChrisTheBaron/pushbullet
Add Pushbullet notification service
2021-08-16 01:06:27 +08:00
LouisLam
7e5a8c896b Merge remote-tracking branch 'chakflying/ping-graph' 2021-08-16 01:00:18 +08:00
Chris Taylor
efe75bde75 Add Pushbullet notification service 2021-08-13 21:18:43 +01:00
Louis Lam
af34e861c5 Merge pull request #200 from proffalken/feature/187_add_cert_checks_to_prometheus
Add certificate monitoring to the Prometheus handler
2021-08-13 00:26:58 +08:00
Louis Lam
2ae2022e62 Merge pull request #211 from AlexandreGagner/master
Add Octopush Notification Service
2021-08-13 00:26:35 +08:00
LouisLam
37f1d60f82 also change meta tag theme-color 2021-08-13 00:23:40 +08:00
LouisLam
d39b43dacc fix require problem 2021-08-13 00:13:46 +08:00
Louis Lam
7ca80fc086 fix auto theme 2021-08-12 22:17:20 +08:00
Alexandre Gagner
eb34dc6cc2 Update notification.js
Fix remove non ascii char from msg
2021-08-12 00:58:51 +02:00
Alexandre Gagner
ed93aae1c2 add octopush notification service 2021-08-12 00:15:53 +02:00
LouisLam
6a8ccf627a add version to user agent 2021-08-12 01:31:07 +08:00
Nelson Chan
8f150aaeb9 Feat: Use Async Component 2021-08-12 00:47:58 +08:00
Nelson Chan
6ed1d8cb2f Feat: Use selective import, improve tooltip UI 2021-08-12 00:31:21 +08:00
Nelson Chan
71bec74081 Feat: Add down-ed bars, improve UI 2021-08-11 23:40:56 +08:00
Nelson Chan
2bd735035c Misc: Show graph by default 2021-08-11 23:40:56 +08:00
Nelson Chan
48c6d8f19f Feat: Display recent ping chart 2021-08-11 23:40:51 +08:00
LouisLam
2d176a38af Merge remote-tracking branch 'origin/master' 2021-08-11 23:38:48 +08:00
LouisLam
b14f63491d timeout change to 80% of its interval 2021-08-11 23:12:38 +08:00
LouisLam
24b87fcd5a update vue to 3.2.1 2021-08-11 22:41:33 +08:00
LouisLam
365ea0a189 add batsh 2021-08-11 14:52:25 +08:00
Louis Lam
2461f5084e Merge pull request #205 from Ponkhy/master
Fixed function buttons for smaller screens
2021-08-11 00:50:43 +08:00
Ponkhy
1d0b332b42 Fixed function buttons for smaller screens 2021-08-10 18:29:47 +02:00
LouisLam
d5149f90b4 fix ping 2021-08-10 22:00:29 +08:00
LouisLam
e0ae9a9e73 improve space-before-function-paren 2021-08-10 21:59:15 +08:00
LouisLam
3227a2660b log undefined ping 2021-08-10 21:47:14 +08:00
LouisLam
764160f38c add eslint: space-before-function-paren 2021-08-10 21:44:29 +08:00
LouisLam
70e7945a66 fix possible race condition 2021-08-10 21:37:51 +08:00
LouisLam
b413427a37 graceful shutdown when listen error 2021-08-10 21:28:54 +08:00
LouisLam
debcac4924 run eslint 2021-08-10 14:24:05 +01:00
Matthew Macdonald-Wallace
268dd33792 Add TLS Info to Prometheus metric output 2021-08-10 14:24:05 +01:00
LouisLam
692a11e51e pass tls info to prometheus.update 2021-08-10 14:24:05 +01:00
Matthew Macdonald-Wallace
5eb4f55dfd Add the new gauges to the prometheus handler 2021-08-10 14:24:05 +01:00
LouisLam
e7cc5340e5 ping ipv6 for macos 2021-08-10 21:07:11 +08:00
LouisLam
4d4d504d6e retry ping domain with ipv6, if domain is not found 2021-08-10 21:03:14 +08:00
LouisLam
2a4695a774 add -6 to ping cmd if ipv6 address 2021-08-10 20:39:58 +08:00
LouisLam
f089bf73c3 Merge remote-tracking branch 'origin/master' 2021-08-10 20:23:29 +08:00
LouisLam
f099e4270d change to Accept: */* to better support all websites 2021-08-10 20:23:15 +08:00
Louis Lam
81636c7b44 Delete reviewdog.yml 2021-08-10 20:03:25 +08:00
Louis Lam
98fa995d3f Update reviewdog.yml 2021-08-10 19:19:55 +08:00
Louis Lam
42d24258cf Delete app.json 2021-08-10 18:41:38 +08:00
Louis Lam
3f56167198 Update reviewdog.yml 2021-08-10 17:56:30 +08:00
Louis Lam
5163e16482 Update reviewdog.yml 2021-08-10 17:36:45 +08:00
LouisLam
d93f6e2716 server.listen bind to ipv6 too 2021-08-10 16:45:37 +08:00
LouisLam
d6fad7f1ef server.listen bind to ipv6 too 2021-08-10 16:36:21 +08:00
LouisLam
5512b15162 add better token for github-pr-review for reviewdog 2021-08-10 15:39:39 +08:00
LouisLam
8979311653 Merge remote-tracking branch 'origin/master' 2021-08-10 15:04:15 +08:00
LouisLam
4f058c5b47 do not fix height for h1 2021-08-10 15:04:01 +08:00
LouisLam
9ba1743900 split mobile mixin from socket mixin 2021-08-10 15:02:46 +08:00
Louis Lam
1e4f9c7e15 Update README.md 2021-08-10 13:10:03 +08:00
Louis Lam
974672f7c1 Delete deploy.template.yaml 2021-08-10 13:09:36 +08:00
Louis Lam
01ac6d54be Merge pull request #199 from chakflying/patch-1
Fix: unify styling of theme switch btn
2021-08-10 12:50:50 +08:00
Nelson Chan
113899e278 Fix: unify styling of theme switch with UI 2021-08-10 12:20:06 +08:00
LouisLam
d1d000bd74 remove red circle around the btn-close while focus 2021-08-10 00:16:13 +08:00
Louis Lam
ef4677a640 Merge pull request #194 from Ponkhy/master
Fixed Close Button Color in Dark Mode
2021-08-10 00:04:25 +08:00
Ponkhy
e39c46ff9b Fixed Close Button Color in Dark Mode 2021-08-09 17:56:44 +02:00
Louis Lam
0e46ce42d1 Update README.md 2021-08-09 22:31:32 +08:00
26 changed files with 713 additions and 289 deletions

View File

@@ -1,11 +0,0 @@
spec:
name: uptime-kuma
services:
- name: server
git:
repo_clone_url: https://github.com/louislam/uptime-kuma
branch: master
http_port: 3001
build_command: npm run setup
run_command: npm run start-server

View File

@@ -36,6 +36,11 @@ module.exports = {
"no-multi-spaces": ["error", { "no-multi-spaces": ["error", {
ignoreEOLComments: true, ignoreEOLComments: true,
}], }],
"space-before-function-paren": ["error", {
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}],
"curly": "error", "curly": "error",
"object-curly-spacing": ["error", "always"], "object-curly-spacing": ["error", "always"],
"object-curly-newline": "off", "object-curly-newline": "off",

View File

@@ -1,12 +0,0 @@
name: reviewdog
on: [pull_request]
jobs:
eslint:
name: runner / eslint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: reviewdog/action-eslint@v1
with:
reporter: github-pr-review
eslint_flags: --ext .js,.ts,.vue .

View File

@@ -1,3 +1,3 @@
{ {
"extends": "stylelint-config-recommended", "extends": "stylelint-config-recommended"
} }

View File

@@ -10,16 +10,16 @@ It is a self-hosted monitoring tool like "Uptime Robot".
<img src="https://louislam.net/uptimekuma/1.jpg" width="512" alt="" /> <img src="https://louislam.net/uptimekuma/1.jpg" width="512" alt="" />
## Features ## Features
* Monitoring uptime for HTTP(s) / TCP / Ping. * Monitoring uptime for HTTP(s) / TCP / Ping.
* Fancy, Reactive, Fast UI/UX. * Fancy, Reactive, Fast UI/UX.
* Notifications via Webhook, Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP) and more by Apprise. * Notifications via Webhook, Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP) and more by Apprise.
* 20 seconds interval. * 20 seconds interval.
## How to Use ## 🔧 How to Install
### Docker ### 🐳 Docker
```bash ```bash
# Create a volume # Create a volume
@@ -31,18 +31,13 @@ docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name upti
Browse to http://localhost:3001 after started. Browse to http://localhost:3001 after started.
Change Port and Volume
```bash If you want to change port and volume, or need to browse via a reserve proxy, please read: https://github.com/louislam/uptime-kuma/wiki/Installation.
docker run -d --restart=always -p <YOUR_PORT>:3001 -v <YOUR_DIR OR VOLUME>:/app/data --name uptime-kuma louislam/uptime-kuma:1
```
### Without Docker (x86/x64 only) ### 💪🏻 Without Docker (Recommanded for x86/x64 only)
Required Tools: Node.js >= 14, git and pm2. Required Tools: Node.js >= 14, git and pm2.
(**Not recommanded for ARM CPU users.** Since there is no prebuilt for node-sqlite3, it is hard to get it running)
```bash ```bash
git clone https://github.com/louislam/uptime-kuma.git git clone https://github.com/louislam/uptime-kuma.git
cd uptime-kuma cd uptime-kuma
@@ -56,42 +51,15 @@ npm run start-server
# Install PM2 if you don't have: npm install pm2 -g # Install PM2 if you don't have: npm install pm2 -g
pm2 start npm --name uptime-kuma -- run start-server pm2 start npm --name uptime-kuma -- run start-server
# Listen to different port or hostname
pm2 start npm --name uptime-kuma -- run start-server -- --port=80 --hostname=0.0.0.0
```
More useful commands if you have installed.
```bash
pm2 start uptime-kuma
pm2 restart uptime-kuma
pm2 stop uptime-kuma
``` ```
Browse to http://localhost:3001 after started. Browse to http://localhost:3001 after started.
### (Optional) One more step for Reverse Proxy If you want to change port and hostname, or need to browse via a reserve proxy, please read: https://github.com/louislam/uptime-kuma/wiki/Installation.
This is optional for someone who want to do reverse proxy. ## 🆙 How to Update
Unlikely other web apps, Uptime Kuma is based on WebSocket. You need two more headers **"Upgrade"** and **"Connection"** in order to reverse proxy WebSocket. ### 🆙🐳 Docker
Please read wiki for more info:
https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy
### One-click Deploy
<!---
Abort. Heroku instance killed the server.js if idle, stupid.
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/louislam/uptime-kuma/tree/1.1.0)
-->
[![Deploy to DO](https://www.deploytodo.com/do-btn-blue.svg)](https://cloud.digitalocean.com/apps/new?repo=https://github.com/louislam/uptime-kuma/tree/master&refcode=e2c7eb658434)
## How to Update
### Docker
Re-pull the latest docker image and create another container with the same volume. Re-pull the latest docker image and create another container with the same volume.
@@ -106,22 +74,27 @@ docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name upti
PS: For every new release, it takes some time to build the docker image, please be patient if it is not available yet. PS: For every new release, it takes some time to build the docker image, please be patient if it is not available yet.
### Without Docker ### 🆙 💪🏻 Without Docker
```bash ```bash
cd <uptime-kuma-directory>
git fetch --all git fetch --all
git checkout 1.1.0 --force git checkout 1.2.0 --force
npm install npm install
npm run build npm run build
pm2 restart uptime-kuma pm2 restart uptime-kuma
``` ```
## What's Next? ## 🆕 What's Next?
I will mark requests/issues to the next milestone. I will mark requests/issues to the next milestone.
https://github.com/louislam/uptime-kuma/milestones https://github.com/louislam/uptime-kuma/milestones
## More Screenshots ## 🖼 More Screenshots
Dark Mode:
<img src="https://user-images.githubusercontent.com/1336778/128710166-908f8d88-9256-43f3-9c49-bfc2c56011d2.png" width="400" alt="" />
Settings Page: Settings Page:
@@ -149,3 +122,5 @@ If you want to report a bug or request a new feature. Free feel to open a new is
If you want to modify Uptime Kuma, this guideline maybe useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md If you want to modify Uptime Kuma, this guideline maybe useful for you: https://github.com/louislam/uptime-kuma/blob/master/CONTRIBUTING.md
English proofreading is needed too, because my grammar is not that great sadly. Feel free to correct my grammar in this Readme, source code or wiki. English proofreading is needed too, because my grammar is not that great sadly. Feel free to correct my grammar in this Readme, source code or wiki.
🐻

View File

@@ -1,7 +0,0 @@
{
"name": "Uptime Kuma",
"description": "A fancy self-hosted monitoring tool",
"repository": "https://github.com/louislam/uptime-kuma",
"logo": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png",
"keywords": ["node", "express", "socket-io", "uptime-kuma", "uptime"]
}

View File

@@ -0,0 +1 @@
docker run -it --rm -v ${pwd}:/app louislam/batsh /usr/bin/batsh bash --output ./install.sh ./extra/install.batsh

View File

@@ -5,8 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/svg+xml" href="/icon.svg" /> <link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"> <meta name="theme-color" id="theme-color" content="" />
<meta name="theme-color" content="#5cdd8b"/>
<meta name="description" content="Uptime Kuma monitoring tool" /> <meta name="description" content="Uptime Kuma monitoring tool" />
<title>Uptime Kuma</title> <title>Uptime Kuma</title>
</head> </head>

290
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "1.0.10", "version": "1.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -756,9 +756,9 @@
} }
}, },
"@types/bootstrap": { "@types/bootstrap": {
"version": "5.0.17", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.0.17.tgz", "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.1.1.tgz",
"integrity": "sha512-uQQQ3p+zw10VjZLvtCuKWI6QgVCYEnK/yHnno3gyEhikfQdiZexS2XPxjWRboGmX135o470GkmCta9eAgQMVLQ==", "integrity": "sha512-W/fEBlqwaJFh+3sCz/H88LPsLt/zLsEECFlrAOkrRPjWuo/ETl8u0JefIerCdc8+WukowQS1f60eIJOwkCBwhg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@popperjs/core": "^2.9.2", "@popperjs/core": "^2.9.2",
@@ -960,45 +960,45 @@
} }
}, },
"@vitejs/plugin-vue": { "@vitejs/plugin-vue": {
"version": "1.3.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.4.0.tgz",
"integrity": "sha512-wJvuJdTBjvucUX0vK4fuy60t+A9bJSZxc59vp1Y+8kiOd0NU5kFt4lay72gMWPeR+lSUjrTmGUq8Uzb99Jbw3A==", "integrity": "sha512-RkqfJHz9wdLKBp5Yi+kQL8BAljdrvPoccQm2PTZc/UcL4EjD11xsv2PPCduYx2oV1a/bpSKA3sD5sxOHFhz+LA==",
"dev": true "dev": true
}, },
"@vue/compiler-core": { "@vue/compiler-core": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.2.tgz",
"integrity": "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==", "integrity": "sha512-QhCI0ZU5nAR0LMcLgzW3v75374tIrHGp8XG5CzJS7Nsy+iuignbE4MZ2XJfh5TGIrtpuzfWA4eTIfukZf/cRdg==",
"requires": { "requires": {
"@babel/parser": "^7.12.0", "@babel/parser": "^7.12.0",
"@babel/types": "^7.12.0", "@babel/types": "^7.12.0",
"@vue/shared": "3.1.5", "@vue/shared": "3.2.2",
"estree-walker": "^2.0.1", "estree-walker": "^2.0.1",
"source-map": "^0.6.1" "source-map": "^0.6.1"
} }
}, },
"@vue/compiler-dom": { "@vue/compiler-dom": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.2.tgz",
"integrity": "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==", "integrity": "sha512-ggcc+NV/ENIE0Uc3TxVE/sKrhYVpLepMAAmEiQ047332mbKOvUkowz4TTFZ+YkgOIuBOPP0XpCxmCMg7p874mA==",
"requires": { "requires": {
"@vue/compiler-core": "3.1.5", "@vue/compiler-core": "3.2.2",
"@vue/shared": "3.1.5" "@vue/shared": "3.2.2"
} }
}, },
"@vue/compiler-sfc": { "@vue/compiler-sfc": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.2.tgz",
"integrity": "sha512-mtMY6xMvZeSRx9MTa1+NgJWndrkzVTdJ1pQAmAKQuxyb5LsHVvrgP7kcQFvxPHVpLVTORbTJWHaiqoKrJvi1iA==", "integrity": "sha512-hrtqpQ5L6IPn5v7yVRo7uvLcQxv0z1+KBjZBWMBOcrXz4t+PKUxU/SWd6Tl9T8FDmYlunzKUh6lcx+2CLo6f5A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/parser": "^7.13.9", "@babel/parser": "^7.13.9",
"@babel/types": "^7.13.0", "@babel/types": "^7.13.0",
"@types/estree": "^0.0.48", "@types/estree": "^0.0.48",
"@vue/compiler-core": "3.1.5", "@vue/compiler-core": "3.2.2",
"@vue/compiler-dom": "3.1.5", "@vue/compiler-dom": "3.2.2",
"@vue/compiler-ssr": "3.1.5", "@vue/compiler-ssr": "3.2.2",
"@vue/shared": "3.1.5", "@vue/shared": "3.2.2",
"consolidate": "^0.16.0", "consolidate": "^0.16.0",
"estree-walker": "^2.0.1", "estree-walker": "^2.0.1",
"hash-sum": "^2.0.0", "hash-sum": "^2.0.0",
@@ -1009,116 +1009,54 @@
"postcss-modules": "^4.0.0", "postcss-modules": "^4.0.0",
"postcss-selector-parser": "^6.0.4", "postcss-selector-parser": "^6.0.4",
"source-map": "^0.6.1" "source-map": "^0.6.1"
},
"dependencies": {
"@vue/compiler-core": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz",
"integrity": "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==",
"dev": true,
"requires": {
"@babel/parser": "^7.12.0",
"@babel/types": "^7.12.0",
"@vue/shared": "3.1.5",
"estree-walker": "^2.0.1",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz",
"integrity": "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==",
"dev": true,
"requires": {
"@vue/compiler-core": "3.1.5",
"@vue/shared": "3.1.5"
}
},
"@vue/shared": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==",
"dev": true
}
} }
}, },
"@vue/compiler-ssr": { "@vue/compiler-ssr": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.2.tgz",
"integrity": "sha512-CU5N7Di/a4lyJ18LGJxJYZS2a8PlLdWpWHX9p/XcsjT2TngMpj3QvHVRkuik2u8QrIDZ8OpYmTyj1WDNsOV+Dg==", "integrity": "sha512-rVl1agMFhdEN3Go0bCriXo+3cysxKIuRP0yh1Wd8ysRrKfAmokyDhUA8PrGSq2Ymj/LdZTh+4OKfj3p2+C+hlA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@vue/compiler-dom": "3.1.5", "@vue/compiler-dom": "3.2.2",
"@vue/shared": "3.1.5" "@vue/shared": "3.2.2"
},
"dependencies": {
"@vue/compiler-core": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz",
"integrity": "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==",
"dev": true,
"requires": {
"@babel/parser": "^7.12.0",
"@babel/types": "^7.12.0",
"@vue/shared": "3.1.5",
"estree-walker": "^2.0.1",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz",
"integrity": "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==",
"dev": true,
"requires": {
"@vue/compiler-core": "3.1.5",
"@vue/shared": "3.1.5"
}
},
"@vue/shared": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==",
"dev": true
}
} }
}, },
"@vue/devtools-api": { "@vue/devtools-api": {
"version": "6.0.0-beta.14", "version": "6.0.0-beta.15",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.14.tgz", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.15.tgz",
"integrity": "sha512-44fPrrN1cqcs6bFkT0C+yxTM6PZXLbR+ESh1U1j8UD22yO04gXvxH62HApMjLbS3WqJO/iCNC+CYT+evPQh2EQ==" "integrity": "sha512-quBx4Jjpexo6KDiNUGFr/zF/2A4srKM9S9v2uHgMXSU//hjgq1eGzqkIFql8T9gfX5ZaVOUzYBP3jIdIR3PKIA=="
}, },
"@vue/reactivity": { "@vue/reactivity": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.2.tgz",
"integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==", "integrity": "sha512-IHjhtmrhK6dzacj/EnLQDWOaA3HuzzVk6w84qgV8EpS4uWGIJXiRalMRg6XvGW2ykJvIl3pLsF0aBFlTMRiLOA==",
"requires": { "requires": {
"@vue/shared": "3.1.5" "@vue/shared": "3.2.2"
} }
}, },
"@vue/runtime-core": { "@vue/runtime-core": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.2.tgz",
"integrity": "sha512-YQbG5cBktN1RowQDKA22itmvQ+b40f0WgQ6CXK4VYoYICAiAfu6Cc14777ve8zp1rJRGtk5oIeS149TOculrTg==", "integrity": "sha512-/aUk1+GO/VPX0oVxhbzSWE1zrf3/wGCsO1ALNisVokYftKqfqLDjbJHE6mrI2hx3MiuwbHrWjJClkGUVTIOPEQ==",
"requires": { "requires": {
"@vue/reactivity": "3.1.5", "@vue/reactivity": "3.2.2",
"@vue/shared": "3.1.5" "@vue/shared": "3.2.2"
} }
}, },
"@vue/runtime-dom": { "@vue/runtime-dom": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.2.tgz",
"integrity": "sha512-tNcf3JhVR0RfW0kw1p8xZgv30nvX8Y9rsz7eiQ0dHe273sfoCngAG0y4GvMaY4Xd8FsjUwFedd4suQ8Lu8meXg==", "integrity": "sha512-1Le/NpCfawCOfePfJezvWUF+oCVLU8N+IHN4oFDOxRe6/PgHNJ+yT+YdxFifBfI+TIAoXI/9PsnqzmJZV+xsmw==",
"requires": { "requires": {
"@vue/runtime-core": "3.1.5", "@vue/runtime-core": "3.2.2",
"@vue/shared": "3.1.5", "@vue/shared": "3.2.2",
"csstype": "^2.6.8" "csstype": "^2.6.8"
} }
}, },
"@vue/shared": { "@vue/shared": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.2.tgz",
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==" "integrity": "sha512-dvYb318tk9uOzHtSaT3WII/HscQSIRzoCZ5GyxEb3JlkEXASpAUAQwKnvSe2CudnF8XHFRTB7VITWSnWNLZUtA=="
}, },
"abbrev": { "abbrev": {
"version": "1.1.1", "version": "1.1.1",
@@ -1779,6 +1717,16 @@
"integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
"dev": true "dev": true
}, },
"chart.js": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.5.0.tgz",
"integrity": "sha512-J1a4EAb1Gi/KbhwDRmoovHTRuqT8qdF0kZ4XgwxpGethJHUdDrkqyPYwke0a+BuvSeUxPf8Cos6AX2AB8H8GLA=="
},
"chartjs-adapter-dayjs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/chartjs-adapter-dayjs/-/chartjs-adapter-dayjs-1.0.0.tgz",
"integrity": "sha512-EnbVqTJGFKLpg1TROLdCEufrzbmIa2oeLGx8O2Wdjw2EoMudoOo9+YFu+6CM0Z0hQ/v3yq/e/Y6efQMu22n8Jg=="
},
"chokidar": { "chokidar": {
"version": "3.5.2", "version": "3.5.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
@@ -1945,9 +1893,9 @@
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
}, },
"core-js": { "core-js": {
"version": "3.16.0", "version": "3.16.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.0.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.1.tgz",
"integrity": "sha512-5+5VxRFmSf97nM8Jr2wzOwLqRo6zphH2aX+7KsAUONObyzakDNq2G/bgbhinxB4PoV9L3aXQYhiDKyIKWd2c8g==", "integrity": "sha512-AAkP8i35EbefU+JddyWi12AWE9f2N/qr/pwnDtWz4nyUIBGMJPX99ANFFRSw6FefM374lDujdtLDyhN2A/btHw==",
"dev": true "dev": true
}, },
"core-util-is": { "core-util-is": {
@@ -2441,9 +2389,9 @@
} }
}, },
"eslint-plugin-vue": { "eslint-plugin-vue": {
"version": "7.15.1", "version": "7.16.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.15.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-7.16.0.tgz",
"integrity": "sha512-4/r+n/i+ovyeW2gVRRH92kpy4lkpFbyPR4BMxGBTLtGnwqOKKzjSo6EMSaT0RhWPvEjK9uifcY8e7z5n8BIEgw==", "integrity": "sha512-0E2dVvVC7I2Xm1HXyx+ZwPj9CNX4NJjs4K4r+GVsHWyt5Pew3JLD4fI7A91b2jeL0TXE7LlszrwLSTJU9eqehw==",
"dev": true, "dev": true,
"requires": { "requires": {
"eslint-utils": "^2.1.0", "eslint-utils": "^2.1.0",
@@ -4789,9 +4737,9 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
}, },
"postcss": { "postcss": {
"version": "8.3.5", "version": "8.3.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.5.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz",
"integrity": "sha512-NxTuJocUhYGsMiMFHDUkmjSKT3EdH4/WbGF6GCi1NDGk+vbcUTun4fpbOqaPtD8IIsztA2ilZm2DhYCuyN58gA==", "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==",
"dev": true, "dev": true,
"requires": { "requires": {
"colorette": "^1.2.2", "colorette": "^1.2.2",
@@ -4874,9 +4822,9 @@
"dev": true "dev": true
}, },
"postcss-modules": { "postcss-modules": {
"version": "4.1.3", "version": "4.2.2",
"resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.1.3.tgz", "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.2.2.tgz",
"integrity": "sha512-dBT39hrXe4OAVYJe/2ZuIZ9BzYhOe7t+IhedYeQ2OxKwDpAGlkEN/fR0fGnrbx4BvgbMReRX4hCubYK9cE/pJQ==", "integrity": "sha512-/H08MGEmaalv/OU8j6bUKi/kZr2kqGF6huAW8m9UAgOLWtpFdhA14+gPBoymtqyv+D4MLsmqaF2zvIegdCxJXg==",
"dev": true, "dev": true,
"requires": { "requires": {
"generic-names": "^2.0.1", "generic-names": "^2.0.1",
@@ -5148,9 +5096,9 @@
"dev": true "dev": true
}, },
"prom-client": { "prom-client": {
"version": "13.1.0", "version": "13.2.0",
"resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.1.0.tgz", "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-13.2.0.tgz",
"integrity": "sha512-jT9VccZCWrJWXdyEtQddCDszYsiuWj5T0ekrPszi/WEegj3IZy6Mm09iOOVM86A4IKMWq8hZkT2dD9MaSe+sng==", "integrity": "sha512-wGr5mlNNdRNzEhRYXgboUU2LxHWIojxscJKmtG3R8f4/KiWqyYgXTLHs0+Ted7tG3zFT7pgHJbtomzZ1L0ARaQ==",
"requires": { "requires": {
"tdigest": "^0.1.1" "tdigest": "^0.1.1"
} }
@@ -6805,13 +6753,82 @@
} }
}, },
"vue": { "vue": {
"version": "3.1.5", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.1.5.tgz", "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.2.tgz",
"integrity": "sha512-Ho7HNb1nfDoO+HVb6qYZgeaobt1XbY6KXFe4HGs1b9X6RhkWG/113n4/SrtM1LUclM6OrP/Se5aPHHvAPG1iVQ==", "integrity": "sha512-D/LuzAV30CgNJYGyNheE/VUs5N4toL2IgmS6c9qeOxvyh0xyn4exyRqizpXIrsvfx34zG9x5gCI2tdRHCGvF9w==",
"requires": { "requires": {
"@vue/compiler-dom": "3.1.5", "@vue/compiler-dom": "3.2.2",
"@vue/runtime-dom": "3.1.5", "@vue/runtime-dom": "3.2.2",
"@vue/shared": "3.1.5" "@vue/shared": "3.2.2"
}
},
"vue-chart-3": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/vue-chart-3/-/vue-chart-3-0.5.7.tgz",
"integrity": "sha512-BccfPv2rodY6IOppYHvMluVmIJE1CHfp5uW2DXrHrm1kIzaafLwpQ5SwdrxuCevn/QhKoi7azzcxwRcoWbX9hg==",
"requires": {
"@vue/runtime-core": "^3.2.1",
"@vue/runtime-dom": "^3.2.1",
"csstype": "^3.0.8",
"lodash": "^4.17.21",
"nanoid": "^3.1.23",
"vue-demi": "^0.10.1"
},
"dependencies": {
"@vue/reactivity": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.1.tgz",
"integrity": "sha512-4Lja2KmyiKvuraDed6dXK2A6+r/7x7xGDA7vVR2Aqc8hQVu0+FWeVX+IBfiVOSpbZXFlHLNmCBFkbuWLQSlgxg==",
"requires": {
"@vue/shared": "3.2.1"
}
},
"@vue/runtime-core": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.1.tgz",
"integrity": "sha512-IsgelRM/5hYeRhz5+ECi66XvYDdjG2t4lARjHvCXw5s9Q4N6uIbjLMwtLzAWRxYf3/y258BrD+ehxAi943ScJg==",
"requires": {
"@vue/reactivity": "3.2.1",
"@vue/shared": "3.2.1"
}
},
"@vue/runtime-dom": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.1.tgz",
"integrity": "sha512-bUAHUSe49A5wYdHQ8wsLU1CMPXaG2fRuv2661mx/6Q9+20QxglT3ss8ZeL6AVRu16JNJMcdvTTsNpbnMbVc/lQ==",
"requires": {
"@vue/runtime-core": "3.2.1",
"@vue/shared": "3.2.1",
"csstype": "^2.6.8"
},
"dependencies": {
"csstype": {
"version": "2.6.17",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.17.tgz",
"integrity": "sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A=="
}
}
},
"@vue/shared": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.1.tgz",
"integrity": "sha512-INN92dVBNgd0TW9BqfQQKx/HWGCHhUUbAV5EZ5FgSCiEdwuZsJbGt1mdnaD9IxGhpiyOjP2ClxGG8SFp7ELcWg=="
},
"csstype": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
"integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"nanoid": {
"version": "3.1.23",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw=="
}
} }
}, },
"vue-confirm-dialog": { "vue-confirm-dialog": {
@@ -6819,6 +6836,11 @@
"resolved": "https://registry.npmjs.org/vue-confirm-dialog/-/vue-confirm-dialog-1.0.2.tgz", "resolved": "https://registry.npmjs.org/vue-confirm-dialog/-/vue-confirm-dialog-1.0.2.tgz",
"integrity": "sha512-gTo1bMDWOLd/6ihmWv8VlPxhc9QaKoE5YqlsKydUOfrrQ3Q3taljF6yI+1TMtAtJLrvZ8DYrePhgBhY1VCJzbQ==" "integrity": "sha512-gTo1bMDWOLd/6ihmWv8VlPxhc9QaKoE5YqlsKydUOfrrQ3Q3taljF6yI+1TMtAtJLrvZ8DYrePhgBhY1VCJzbQ=="
}, },
"vue-demi": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.10.1.tgz",
"integrity": "sha512-L6Oi+BvmMv6YXvqv5rJNCFHEKSVu7llpWWJczqmAQYOdmPPw5PNYoz1KKS//Fxhi+4QP64dsPjtmvnYGo1jemA=="
},
"vue-eslint-parser": { "vue-eslint-parser": {
"version": "7.10.0", "version": "7.10.0",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.10.0.tgz", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.10.0.tgz",
@@ -6865,9 +6887,9 @@
"integrity": "sha512-Xp9fGJECns45v+v8jXbCIsAkCybYkEg0lNwr7Z6HDUSMyx2TEIK2giipPE+qXiShEc1Ipn+ZtttH2iq9hwXP4Q==" "integrity": "sha512-Xp9fGJECns45v+v8jXbCIsAkCybYkEg0lNwr7Z6HDUSMyx2TEIK2giipPE+qXiShEc1Ipn+ZtttH2iq9hwXP4Q=="
}, },
"vue-router": { "vue-router": {
"version": "4.0.10", "version": "4.0.11",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.10.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.0.11.tgz",
"integrity": "sha512-YbPf6QnZpyyWfnk7CUt2Bme+vo7TLfg1nGZNkvYqKYh4vLaFw6Gn8bPGdmt5m4qrGnKoXLqc4htAsd3dIukICA==", "integrity": "sha512-sha6I8fx9HWtvTrFZfxZkiQQBpqSeT+UCwauYjkdOQYRvwsGwimlQQE2ayqUwuuXGzquFpCPoXzYKWlzL4OuXg==",
"requires": { "requires": {
"@vue/devtools-api": "^6.0.0-beta.14" "@vue/devtools-api": "^6.0.0-beta.14"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "1.1.0", "version": "1.2.0",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -13,27 +13,32 @@
"dev": "vite --host", "dev": "vite --host",
"start": "npm run start-server", "start": "npm run start-server",
"start-server": "node server/server.js", "start-server": "node server/server.js",
"start-demo-server": "set NODE_ENV=demo && node server/server.js",
"update": "", "update": "",
"build": "vite build", "build": "vite build",
"vite-preview-dist": "vite preview --host", "vite-preview-dist": "vite preview --host",
"build-docker": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.1.0 --target release . --push", "build-docker": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.2.0 --target release . --push",
"build-docker-nightly": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push", "build-docker-nightly": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
"build-docker-nightly-amd64": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push", "build-docker-nightly-amd64": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push",
"setup": "git checkout 1.1.0 && npm install && npm run build", "setup": "git checkout 1.2.0 && npm install && npm run build",
"update-version": "node extra/update-version.js", "update-version": "node extra/update-version.js",
"mark-as-nightly": "node extra/mark-as-nightly.js", "mark-as-nightly": "node extra/mark-as-nightly.js",
"reset-password": "node extra/reset-password.js" "reset-password": "node extra/reset-password.js",
"compile-install-script": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./extra/compile-install-script.ps1"
}, },
"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-4", "@fortawesome/vue-fontawesome": "^3.0.0-4",
"@louislam/sqlite3": "^5.0.3",
"@popperjs/core": "^2.9.3", "@popperjs/core": "^2.9.3",
"args-parser": "^1.3.0", "args-parser": "^1.3.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"bootstrap": "^5.1.0", "bootstrap": "^5.1.0",
"chart.js": "^3.5.0",
"chartjs-adapter-dayjs": "^1.0.0",
"command-exists": "^1.2.9", "command-exists": "^1.2.9",
"dayjs": "^1.10.6", "dayjs": "^1.10.6",
"express": "^4.17.1", "express": "^4.17.1",
@@ -43,29 +48,29 @@
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"nodemailer": "^6.6.3", "nodemailer": "^6.6.3",
"password-hash": "^1.2.2", "password-hash": "^1.2.2",
"prom-client": "^13.1.0", "prom-client": "^13.2.0",
"prometheus-api-metrics": "^3.2.0", "prometheus-api-metrics": "^3.2.0",
"redbean-node": "0.0.21", "redbean-node": "0.0.21",
"socket.io": "^4.1.3", "socket.io": "^4.1.3",
"socket.io-client": "^4.1.3", "socket.io-client": "^4.1.3",
"@louislam/sqlite3": "^5.0.3",
"tcp-ping": "^0.1.1", "tcp-ping": "^0.1.1",
"v-pagination-3": "^0.1.6", "v-pagination-3": "^0.1.6",
"vue": "^3.1.5", "vue": "^3.2.2",
"vue-chart-3": "^0.5.7",
"vue-confirm-dialog": "^1.0.2", "vue-confirm-dialog": "^1.0.2",
"vue-multiselect": "^3.0.0-alpha.2", "vue-multiselect": "^3.0.0-alpha.2",
"vue-router": "^4.0.10", "vue-router": "^4.0.11",
"vue-toastification": "^2.0.0-rc.1" "vue-toastification": "^2.0.0-rc.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.15.0", "@babel/eslint-parser": "^7.15.0",
"@types/bootstrap": "^5.0.17", "@types/bootstrap": "^5.1.1",
"@vitejs/plugin-legacy": "^1.5.1", "@vitejs/plugin-legacy": "^1.5.1",
"@vitejs/plugin-vue": "^1.3.0", "@vitejs/plugin-vue": "^1.4.0",
"@vue/compiler-sfc": "^3.1.5", "@vue/compiler-sfc": "^3.2.2",
"core-js": "^3.16.0", "core-js": "^3.16.1",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-vue": "^7.15.1", "eslint-plugin-vue": "^7.16.0",
"sass": "^1.37.5", "sass": "^1.37.5",
"stylelint": "^13.13.1", "stylelint": "^13.13.1",
"stylelint-config-recommended": "^5.0.0", "stylelint-config-recommended": "^5.0.0",

View File

@@ -11,6 +11,7 @@ const { tcping, ping, checkCertificate, checkStatusCode } = require("../util-ser
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")
const version = require("../../package.json").version;
/** /**
* status: * status:
@@ -79,6 +80,10 @@ class Monitor extends BeanModel {
const beat = async () => { const beat = async () => {
// Expose here for prometheus update
// undefined if not https
let tlsInfo = undefined;
if (! previousBeat) { if (! previousBeat) {
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,
@@ -110,9 +115,10 @@ class Monitor extends BeanModel {
// Use Custom agent to disable session reuse // Use Custom agent to disable session reuse
// https://github.com/nodejs/node/issues/3940 // https://github.com/nodejs/node/issues/3940
let res = await axios.get(this.url, { let res = await axios.get(this.url, {
timeout: 15000, timeout: this.interval * 1000 * 0.8,
headers: { headers: {
"User-Agent": "Uptime-Kuma", "Accept": "*/*",
"User-Agent": "Uptime-Kuma/" + version,
}, },
httpsAgent: new https.Agent({ httpsAgent: new https.Agent({
maxCachedSessions: 0, maxCachedSessions: 0,
@@ -131,7 +137,7 @@ class Monitor extends BeanModel {
let certInfoStartTime = dayjs().valueOf(); let certInfoStartTime = dayjs().valueOf();
if (this.getUrl()?.protocol === "https:") { if (this.getUrl()?.protocol === "https:") {
try { try {
await this.updateTlsInfo(checkCertificate(res)); tlsInfo = await this.updateTlsInfo(checkCertificate(res));
} catch (e) { } catch (e) {
if (e.message !== "No TLS certificate in response") { if (e.message !== "No TLS certificate in response") {
console.error(e.message) console.error(e.message)
@@ -253,7 +259,7 @@ class Monitor extends BeanModel {
console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Type: ${this.type}`) console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Type: ${this.type}`)
} }
prometheus.update(bean) prometheus.update(bean, tlsInfo)
io.to(this.user_id).emit("heartbeat", bean.toJSON()); io.to(this.user_id).emit("heartbeat", bean.toJSON());
@@ -288,7 +294,7 @@ class Monitor extends BeanModel {
/** /**
* Store TLS info to database * Store TLS info to database
* @param checkCertificateResult * @param checkCertificateResult
* @returns {Promise<void>} * @returns {Promise<object>}
*/ */
async updateTlsInfo(checkCertificateResult) { async updateTlsInfo(checkCertificateResult) {
let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [ let tls_info_bean = await R.findOne("monitor_tls_info", "monitor_id = ?", [
@@ -300,6 +306,8 @@ class Monitor extends BeanModel {
} }
tls_info_bean.info_json = JSON.stringify(checkCertificateResult); tls_info_bean.info_json = JSON.stringify(checkCertificateResult);
await R.store(tls_info_bean); await R.store(tls_info_bean);
return checkCertificateResult;
} }
static async sendStats(io, monitorID, userID) { static async sendStats(io, monitorID, userID) {

View File

@@ -193,6 +193,34 @@ class Notification {
console.log(error) console.log(error)
return false; return false;
} }
} else if (notification.type === "octopush") {
try {
let config = {
headers: {
'api-key': notification.octopushAPIKey,
'api-login': notification.octopushLogin,
'cache-control': 'no-cache'
}
};
let data = {
"recipients": [
{
"phone_number": notification.octopushPhoneNumber
}
],
//octopush not supporting non ascii char
"text": msg.replace(/[^\x00-\x7F]/g, ""),
"type": notification.octopushSMSType,
"purpose": "alert",
"sender": notification.octopushSenderName
};
await axios.post(`https://api.octopush.com/v1/public/sms-campaign/send`, data, config)
return true;
} catch (error) {
console.log(error)
return false;
}
} else if (notification.type === "slack") { } else if (notification.type === "slack") {
try { try {
if (heartbeatJSON == null) { if (heartbeatJSON == null) {
@@ -326,6 +354,41 @@ class Notification {
throwGeneralAxiosError(error) throwGeneralAxiosError(error)
} }
} else if (notification.type === "pushbullet") {
try {
let pushbulletUrl = `https://api.pushbullet.com/v2/pushes`;
let config = {
headers: {
'Access-Token': notification.pushbulletAccessToken,
'Content-Type': 'application/json'
}
};
if (heartbeatJSON == null) {
let testdata = {
"type": "note",
"title": "Uptime Kuma Alert",
"body": "Testing Successful.",
}
await axios.post(pushbulletUrl, testdata, config)
} else if (heartbeatJSON["status"] == 0) {
let downdata = {
"type": "note",
"title": "UptimeKuma Alert:" + monitorJSON["name"],
"body": "[🔴 Down]" + heartbeatJSON["msg"] + "\nTime (UTC):" + heartbeatJSON["time"],
}
await axios.post(pushbulletUrl, downdata, config)
} else if (heartbeatJSON["status"] == 1) {
let updata = {
"type": "note",
"title": "UptimeKuma Alert:" + monitorJSON["name"],
"body": "[✅ Up]" + heartbeatJSON["msg"] + "\nTime (UTC):" + heartbeatJSON["time"],
}
await axios.post(pushbulletUrl, updata, config)
}
return okMsg;
} catch (error) {
throwGeneralAxiosError(error)
}
} else { } else {
throw new Error("Notification type is not supported") throw new Error("Notification type is not supported")
} }

View File

@@ -1,12 +1,13 @@
// https://github.com/ben-bradley/ping-lite/blob/master/ping-lite.js // https://github.com/ben-bradley/ping-lite/blob/master/ping-lite.js
// Fixed on Windows // Fixed on Windows
const net = require("net");
let spawn = require("child_process").spawn, const spawn = require("child_process").spawn,
events = require("events"), events = require("events"),
fs = require("fs"), fs = require("fs"),
WIN = /^win/.test(process.platform), WIN = /^win/.test(process.platform),
LIN = /^linux/.test(process.platform), LIN = /^linux/.test(process.platform),
MAC = /^darwin/.test(process.platform); MAC = /^darwin/.test(process.platform);
const { debug } = require("../src/util");
module.exports = Ping; module.exports = Ping;
@@ -24,14 +25,30 @@ function Ping(host, options) {
this._bin = "c:/windows/system32/ping.exe"; this._bin = "c:/windows/system32/ping.exe";
this._args = (options.args) ? options.args : [ "-n", "1", "-w", "5000", host ]; this._args = (options.args) ? options.args : [ "-n", "1", "-w", "5000", host ];
this._regmatch = /[><=]([0-9.]+?)ms/; this._regmatch = /[><=]([0-9.]+?)ms/;
} else if (LIN) { } else if (LIN) {
this._bin = "/bin/ping"; this._bin = "/bin/ping";
this._args = (options.args) ? options.args : [ "-n", "-w", "2", "-c", "1", host ];
this._regmatch = /=([0-9.]+?) ms/; // need to verify this const defaultArgs = [ "-n", "-w", "2", "-c", "1", host ];
if (net.isIPv6(host) || options.ipv6) {
defaultArgs.unshift("-6");
}
this._args = (options.args) ? options.args : defaultArgs;
this._regmatch = /=([0-9.]+?) ms/;
} else if (MAC) { } else if (MAC) {
if (net.isIPv6(host) || options.ipv6) {
this._bin = "/sbin/ping6";
} else {
this._bin = "/sbin/ping"; this._bin = "/sbin/ping";
}
this._args = (options.args) ? options.args : [ "-n", "-t", "2", "-c", "1", host ]; this._args = (options.args) ? options.args : [ "-n", "-t", "2", "-c", "1", host ];
this._regmatch = /=([0-9.]+?) ms/; this._regmatch = /=([0-9.]+?) ms/;
} else { } else {
throw new Error("Could not detect your ping binary."); throw new Error("Could not detect your ping binary.");
} }
@@ -105,7 +122,7 @@ Ping.prototype.send = function(callback) {
ms = stdout.match(self._regmatch); // parse out the ##ms response ms = stdout.match(self._regmatch); // parse out the ##ms response
ms = (ms && ms[1]) ? Number(ms[1]) : ms; ms = (ms && ms[1]) ? Number(ms[1]) : ms;
callback(null, ms); callback(null, ms, stdout);
} }
}; };

View File

@@ -1,22 +1,33 @@
const PrometheusClient = require('prom-client'); const PrometheusClient = require("prom-client");
const commonLabels = [ const commonLabels = [
'monitor_name', "monitor_name",
'monitor_type', "monitor_type",
'monitor_url', "monitor_url",
'monitor_hostname', "monitor_hostname",
'monitor_port', "monitor_port",
] ]
const monitor_cert_days_remaining = new PrometheusClient.Gauge({
name: "monitor_cert_days_remaining",
help: "The number of days remaining until the certificate expires",
labelNames: commonLabels
});
const monitor_cert_is_valid = new PrometheusClient.Gauge({
name: "monitor_cert_is_valid",
help: "Is the certificate still valid? (1 = Yes, 0= No)",
labelNames: commonLabels
});
const monitor_response_time = new PrometheusClient.Gauge({ const monitor_response_time = new PrometheusClient.Gauge({
name: 'monitor_response_time', name: "monitor_response_time",
help: 'Monitor Response Time (ms)', help: "Monitor Response Time (ms)",
labelNames: commonLabels labelNames: commonLabels
}); });
const monitor_status = new PrometheusClient.Gauge({ const monitor_status = new PrometheusClient.Gauge({
name: 'monitor_status', name: "monitor_status",
help: 'Monitor Status (1 = UP, 0= DOWN)', help: "Monitor Status (1 = UP, 0= DOWN)",
labelNames: commonLabels labelNames: commonLabels
}); });
@@ -33,7 +44,27 @@ class Prometheus {
} }
} }
update(heartbeat) { update(heartbeat, tlsInfo) {
if (typeof tlsInfo !== "undefined") {
try {
let is_valid = 0
if (tlsInfo.valid == true) {
is_valid = 1
} else {
is_valid = 0
}
monitor_cert_is_valid.set(this.monitorLabelValues, is_valid)
} catch (e) {
console.error(e)
}
try {
monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.daysRemaining)
} catch (e) {
console.error(e)
}
}
try { try {
monitor_status.set(this.monitorLabelValues, heartbeat.status) monitor_status.set(this.monitorLabelValues, heartbeat.status)
} catch (e) { } catch (e) {
@@ -41,7 +72,7 @@ class Prometheus {
} }
try { try {
if (typeof heartbeat.ping === 'number') { if (typeof heartbeat.ping === "number") {
monitor_response_time.set(this.monitorLabelValues, heartbeat.ping) monitor_response_time.set(this.monitorLabelValues, heartbeat.ping)
} else { } else {
// Is it good? // Is it good?

View File

@@ -40,7 +40,11 @@ const passwordHash = require("./password-hash");
const args = require("args-parser")(process.argv); const args = require("args-parser")(process.argv);
const version = require("../package.json").version; const version = require("../package.json").version;
const hostname = process.env.HOST || args.host || "0.0.0.0"
// If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available and the unspecified IPv4 address (0.0.0.0) otherwise.
// Dual-stack support for (::)
const hostname = process.env.HOST || args.host;
const port = parseInt(process.env.PORT || args.port || 3001); const port = parseInt(process.env.PORT || args.port || 3001);
console.info("Version: " + version) console.info("Version: " + version)
@@ -566,16 +570,26 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString();
}); });
console.log("Init") console.log("Init the server")
server.once("error", async (err) => {
console.error("Cannot listen: " + err.message);
await Database.close();
});
server.listen(port, hostname, () => { server.listen(port, hostname, () => {
if (hostname) {
console.log(`Listening on ${hostname}:${port}`); console.log(`Listening on ${hostname}:${port}`);
} else {
console.log(`Listening on ${port}`);
}
startMonitors(); startMonitors();
}); });
})(); })();
async function updateMonitorNotification(monitorID, notificationIDList) { async function updateMonitorNotification(monitorID, notificationIDList) {
R.exec("DELETE FROM monitor_notification WHERE monitor_id = ? ", [ await R.exec("DELETE FROM monitor_notification WHERE monitor_id = ? ", [
monitorID, monitorID,
]) ])

View File

@@ -45,15 +45,30 @@ exports.tcping = function (hostname, port) {
}); });
} }
exports.ping = function (hostname) { exports.ping = async (hostname) => {
return new Promise((resolve, reject) => { try {
const ping = new Ping(hostname); return await exports.pingAsync(hostname);
} catch (e) {
// If the host cannot be resolved, try again with ipv6
if (e.message.includes("service not known")) {
return await exports.pingAsync(hostname, true);
} else {
throw e;
}
}
}
ping.send(function (err, ms) { exports.pingAsync = function (hostname, ipv6 = false) {
return new Promise((resolve, reject) => {
const ping = new Ping(hostname, {
ipv6
});
ping.send(function (err, ms, stdout) {
if (err) { if (err) {
reject(err) reject(err);
} else if (ms === null) { } else if (ms === null) {
reject(new Error("timeout")) reject(new Error(stdout))
} else { } else {
resolve(Math.round(ms)) resolve(Math.round(ms))
} }

View File

@@ -6,8 +6,7 @@
} }
h1 { h1 {
font-size: 31px; font-size: 32px;
height: 38px;
} }
h2 { h2 {
@@ -132,7 +131,12 @@ h2 {
} }
.btn-close { .btn-close {
opacity: 1; box-shadow: none;
filter: invert(1);
&:hover {
opacity: 0.6;
}
} }
.modal-header { .modal-header {

View File

@@ -22,8 +22,10 @@
<option value="slack">Slack</option> <option value="slack">Slack</option>
<option value="pushover">Pushover</option> <option value="pushover">Pushover</option>
<option value="pushy">Pushy</option> <option value="pushy">Pushy</option>
<option value="octopush">Octopush</option>
<option value="lunasea">LunaSea</option> <option value="lunasea">LunaSea</option>
<option value="apprise">Apprise (Support 50+ Notification services)</option> <option value="apprise">Apprise (Support 50+ Notification services)</option>
<option value="pushbullet">Pushbullet</option>
</select> </select>
</div> </div>
@@ -252,6 +254,37 @@
</p> </p>
</template> </template>
<template v-if="notification.type === 'octopush'">
<div class="mb-3">
<label for="octopush-key" class="form-label">API KEY</label>
<input id="octopush-key" v-model="notification.octopushAPIKey" type="text" class="form-control" required>
<label for="octopush-login" class="form-label">API LOGIN</label>
<input id="octopush-login" v-model="notification.octopushLogin" type="text" class="form-control" required>
</div>
<div class="mb-3">
<label for="octopush-type-sms" class="form-label">SMS Type</label>
<select id="octopush-type-sms" v-model="notification.octopushSMSType" class="form-select">
<option value="sms_premium">Premium (Fast - recommended for alerting)</option>
<option value="sms_low_cost">Low Cost (Slow, sometimes blocked by operator)</option>
</select>
<div class="form-text">
Check octopush prices <a href="https://octopush.com/tarifs-sms-international/" target="_blank">https://octopush.com/tarifs-sms-international/</a>.
</div>
</div>
<div class="mb-3">
<label for="octopush-phone-number" class="form-label">Phone number (intl format, eg : +33612345678) </label>
<input id="octopush-phone-number" v-model="notification.octopushPhoneNumber" type="text" class="form-control" required>
</div>
<div class="mb-3">
<label for="octopush-sender-name" class="form-label">SMS Sender Name : 3-11 alphanumeric characters and space (a-zA-Z0-9)</label>
<input id="octopush-sender-name" v-model="notification.octopushSenderName" type="text" minlength="3" maxlength="11" class="form-control">
</div>
<p style="margin-top: 8px;">
More info on: <a href="https://octopush.com/api-sms-documentation/envoi-de-sms/" target="_blank">https://octopush.com/api-sms-documentation/envoi-de-sms/</a>
</p>
</template>
<template v-if="notification.type === 'pushover'"> <template v-if="notification.type === 'pushover'">
<div class="mb-3"> <div class="mb-3">
<label for="pushover-user" class="form-label">User Key<span style="color:red;"><sup>*</sup></span></label> <label for="pushover-user" class="form-label">User Key<span style="color:red;"><sup>*</sup></span></label>
@@ -339,6 +372,17 @@
</div> </div>
</div> </div>
</template> </template>
<template v-if="notification.type === 'pushbullet'">
<div class="mb-3">
<label for="pushbullet-access-token" class="form-label">Access Token</label>
<input id="pushbullet-access-token" v-model="notification.pushbulletAccessToken" type="text" class="form-control" required>
</div>
<p style="margin-top: 8px;">
More info on: <a href="https://docs.pushbullet.com" target="_blank">https://docs.pushbullet.com</a>
</p>
</template>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button v-if="id" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm"> <button v-if="id" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm">

View File

@@ -0,0 +1,152 @@
<template>
<LineChart :chart-data="chartData" :height="100" :options="chartOptions" />
</template>
<script>
import { BarController, BarElement, Chart, Filler, LinearScale, LineController, LineElement, PointElement, TimeScale, Tooltip } from "chart.js";
import dayjs from "dayjs";
import utc from "dayjs/plugin/utc";
import timezone from "dayjs/plugin/timezone";
import "chartjs-adapter-dayjs";
import { LineChart } from "vue-chart-3";
dayjs.extend(utc);
dayjs.extend(timezone);
Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler);
export default {
components: { LineChart },
props: {
monitorId: {
type: Number,
required: true,
},
},
data() {
return {
chartPeriodHrs: 6,
};
},
computed: {
chartOptions() {
return {
responsive: true,
layout: {
padding: {
left: 10,
right: 30,
top: 30,
bottom: 10,
},
},
elements: {
point: {
radius: 0,
},
bar: {
barThickness: "flex",
}
},
scales: {
x: {
type: "time",
time: {
unit: "minute",
},
ticks: {
maxRotation: 0,
autoSkipPadding: 10,
},
grid: {
color: this.$root.theme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)",
},
},
y: {
title: {
display: true,
text: "Response Time (ms)",
},
offset: false,
grid: {
color: this.$root.theme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)",
},
},
y1: {
display: false,
position: "right",
grid: {
drawOnChartArea: false,
},
min: 0,
max: 1,
offset: false,
},
},
bounds: "ticks",
plugins: {
tooltip: {
mode: "nearest",
intersect: false,
padding: 10,
filter: function (tooltipItem) {
return tooltipItem.datasetIndex === 0;
},
callbacks: {
label: (context) => {
return ` ${new Intl.NumberFormat().format(context.parsed.y)} ms`
},
}
},
legend: {
display: false,
},
},
}
},
chartData() {
let ping_data = [];
let down_data = [];
if (this.monitorId in this.$root.heartbeatList) {
ping_data = this.$root.heartbeatList[this.monitorId]
.filter(
(beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter(dayjs().subtract(this.chartPeriodHrs, "hours")))
.map((beat) => {
return {
x: dayjs.utc(beat.time).tz(this.$root.timezone).format("YYYY-MM-DD HH:mm:ss"),
y: beat.ping,
};
});
down_data = this.$root.heartbeatList[this.monitorId]
.filter(
(beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter(dayjs().subtract(this.chartPeriodHrs, "hours")))
.map((beat) => {
return {
x: dayjs.utc(beat.time).tz(this.$root.timezone).format("YYYY-MM-DD HH:mm:ss"),
y: beat.status === 0 ? 1 : 0,
};
});
}
return {
datasets: [
{
data: ping_data,
fill: "origin",
tension: 0.2,
borderColor: "#5CDD8B",
backgroundColor: "#5CDD8B38",
yAxisID: "y",
},
{
type: "bar",
data: down_data,
borderColor: "#00000000",
backgroundColor: "#DC354568",
yAxisID: "y1",
},
],
};
},
},
};
</script>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div :class="$root.theme"> <div :class="classes">
<div v-if="! $root.socket.connected && ! $root.socket.firstConnect" class="lost-connection"> <div v-if="! $root.socket.connected && ! $root.socket.firstConnect" class="lost-connection">
<div class="container-fluid"> <div class="container-fluid">
{{ $root.connectionErrorMsg }} {{ $root.connectionErrorMsg }}
@@ -79,29 +79,45 @@
import Login from "../components/Login.vue"; import Login from "../components/Login.vue";
export default { export default {
components: { components: {
Login, Login,
}, },
data() { data() {
return {} return {}
}, },
computed: {},
computed: {
// Theme or Mobile
classes() {
const classes = {};
classes[this.$root.theme] = true;
classes["mobile"] = this.$root.isMobile;
return classes;
}
},
watch: { watch: {
$route (to, from) { $route (to, from) {
this.init(); this.init();
}, },
}, },
mounted() { mounted() {
this.init(); this.init();
}, },
methods: { methods: {
init() { init() {
if (this.$route.name === "root") { if (this.$route.name === "root") {
this.$router.push("/dashboard") this.$router.push("/dashboard")
} }
}, },
}, },
} }
</script> </script>

View File

@@ -10,6 +10,7 @@ import EmptyLayout from "./layouts/EmptyLayout.vue";
import Layout from "./layouts/Layout.vue"; import Layout from "./layouts/Layout.vue";
import socket from "./mixins/socket"; import socket from "./mixins/socket";
import theme from "./mixins/theme"; import theme from "./mixins/theme";
import mobile from "./mixins/mobile";
import Dashboard from "./pages/Dashboard.vue"; import Dashboard from "./pages/Dashboard.vue";
import DashboardHome from "./pages/DashboardHome.vue"; import DashboardHome from "./pages/DashboardHome.vue";
import Details from "./pages/Details.vue"; import Details from "./pages/Details.vue";
@@ -78,7 +79,8 @@ const router = createRouter({
const app = createApp({ const app = createApp({
mixins: [ mixins: [
socket, socket,
theme theme,
mobile
], ],
data() { data() {
return { return {

25
src/mixins/mobile.js Normal file
View File

@@ -0,0 +1,25 @@
export default {
data() {
return {
windowWidth: window.innerWidth,
}
},
created() {
window.addEventListener("resize", this.onResize);
},
methods: {
onResize() {
this.windowWidth = window.innerWidth;
},
},
computed: {
isMobile() {
return this.windowWidth <= 767.98;
},
}
}

View File

@@ -27,7 +27,6 @@ export default {
uptimeList: { }, uptimeList: { },
certInfoList: {}, certInfoList: {},
notificationList: [], notificationList: [],
windowWidth: window.innerWidth,
showListMobile: false, showListMobile: false,
connectionErrorMsg: "Cannot connect to the socket server. Reconnecting...", connectionErrorMsg: "Cannot connect to the socket server. Reconnecting...",
} }
@@ -193,10 +192,6 @@ export default {
this.$root.showListMobile = false; this.$root.showListMobile = false;
}, },
onResize() {
this.windowWidth = window.innerWidth;
},
storage() { storage() {
return (this.remember) ? localStorage : sessionStorage; return (this.remember) ? localStorage : sessionStorage;
}, },
@@ -270,10 +265,6 @@ export default {
computed: { computed: {
isMobile() {
return this.windowWidth <= 767.98;
},
timezone() { timezone() {
if (this.userTimezone === "auto") { if (this.userTimezone === "auto") {

View File

@@ -2,7 +2,7 @@ export default {
data() { data() {
return { return {
system: (window.matchMedia("(prefers-color-scheme: dark)")) ? "dark" : "light", system: (window.matchMedia("(prefers-color-scheme: dark)").matches) ? "dark" : "light",
userTheme: localStorage.theme, userTheme: localStorage.theme,
}; };
}, },
@@ -14,6 +14,7 @@ export default {
} }
document.body.classList.add(this.theme); document.body.classList.add(this.theme);
this.updateThemeColorMeta();
}, },
computed: { computed: {
@@ -33,6 +34,17 @@ export default {
theme(to, from) { theme(to, from) {
document.body.classList.remove(from); document.body.classList.remove(from);
document.body.classList.add(this.theme); document.body.classList.add(this.theme);
this.updateThemeColorMeta();
}
},
methods: {
updateThemeColorMeta() {
if (this.theme === "dark") {
document.querySelector("#theme-color").setAttribute("content", "#161B22");
} else {
document.querySelector("#theme-color").setAttribute("content", "#5cdd8b");
}
} }
} }
} }

View File

@@ -42,7 +42,11 @@
<div class="col"> <div class="col">
<h4>{{ pingTitle }}</h4> <h4>{{ pingTitle }}</h4>
<p>(Current)</p> <p>(Current)</p>
<span class="num"><CountUp :value="ping" /></span> <span class="num">
<a href="#" @click.prevent="showPingChartBox = !showPingChartBox">
<CountUp :value="ping" />
</a>
</span>
</div> </div>
<div class="col"> <div class="col">
<h4>Avg. {{ pingTitle }}</h4> <h4>Avg. {{ pingTitle }}</h4>
@@ -70,6 +74,14 @@
</div> </div>
</div> </div>
<div v-if="showPingChartBox" class="shadow-box big-padding text-center">
<div class="row">
<div class="col">
<PingChart :monitor-id="monitor.id" />
</div>
</div>
</div>
<div v-if="showCertInfoBox" class="shadow-box big-padding text-center"> <div v-if="showCertInfoBox" class="shadow-box big-padding text-center">
<div class="row"> <div class="row">
<div class="col"> <div class="col">
@@ -155,6 +167,7 @@
</template> </template>
<script> <script>
import { defineAsyncComponent } from "vue";
import { useToast } from "vue-toastification" import { useToast } from "vue-toastification"
const toast = useToast() const toast = useToast()
import Confirm from "../components/Confirm.vue"; import Confirm from "../components/Confirm.vue";
@@ -164,6 +177,7 @@ import Datetime from "../components/Datetime.vue";
import CountUp from "../components/CountUp.vue"; import CountUp from "../components/CountUp.vue";
import Uptime from "../components/Uptime.vue"; import Uptime from "../components/Uptime.vue";
import Pagination from "v-pagination-3"; import Pagination from "v-pagination-3";
const PingChart = defineAsyncComponent(() => import("../components/PingChart.vue"));
export default { export default {
components: { components: {
@@ -174,6 +188,7 @@ export default {
Confirm, Confirm,
Status, Status,
Pagination, Pagination,
PingChart,
}, },
data() { data() {
return { return {
@@ -181,6 +196,7 @@ export default {
perPage: 25, perPage: 25,
heartBeatList: [], heartBeatList: [],
toggleCertInfoBox: false, toggleCertInfoBox: false,
showPingChartBox: true,
} }
}, },
computed: { computed: {
@@ -306,6 +322,31 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../assets/vars.scss"; @import "../assets/vars.scss";
@media (max-width: 550px) {
.functions {
text-align: center;
}
button, a {
margin-left: 10px !important;
margin-right: 10px !important;
}
}
@media (max-width: 400px) {
.btn {
display: inline-flex;
flex-direction: column;
align-items: center;
padding-top: 10px;
}
a.btn {
padding-left: 25px;
padding-right: 25px;
}
}
.url { .url {
color: $primary; color: $primary;
margin-bottom: 20px; margin-bottom: 20px;

View File

@@ -248,10 +248,22 @@ export default {
padding: 20px; padding: 20px;
} }
.btn-check:active + .btn-outline-primary,
.btn-check:checked + .btn-outline-primary,
.btn-check:hover + .btn-outline-primary {
color: #fff;
}
.dark { .dark {
.list-group-item { .list-group-item {
background-color: $dark-bg2; background-color: $dark-bg2;
color: $dark-font-color; color: $dark-font-color;
} }
.btn-check:active + .btn-outline-primary,
.btn-check:checked + .btn-outline-primary,
.btn-check:hover + .btn-outline-primary {
color: #000;
}
} }
</style> </style>