mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-13 23:17:00 +08:00
Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
78f5d2cd8b | ||
|
f62b70c9a9 | ||
|
dfa9b3a0ca | ||
|
b3bff8d735 | ||
|
f2af5bc064 | ||
|
91b736f391 | ||
|
275f77d4bb | ||
|
b00524067a | ||
|
25a93b05dc | ||
|
53e203d2f9 | ||
|
f48f957ba9 | ||
|
bfb117cb76 | ||
|
2b8e33caed | ||
|
60493f0f86 | ||
|
63c6e29e62 | ||
|
5f6d5588a6 | ||
|
18744d834f | ||
|
8dd5b97b79 | ||
|
386c8bfdf1 | ||
|
126f00e739 | ||
|
80466ac957 | ||
|
3b52433202 | ||
|
137f5da3da | ||
|
338d002d42 | ||
|
77ab9fbc57 | ||
|
b6b7835d7e | ||
|
d4fe5908f5 |
@@ -2,3 +2,4 @@
|
|||||||
/dist
|
/dist
|
||||||
/node_modules
|
/node_modules
|
||||||
/data/kuma.db
|
/data/kuma.db
|
||||||
|
/.do
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
# Uptime Kuma
|
# Uptime Kuma
|
||||||
|
|
||||||
|
<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a>
|
||||||
|
|
||||||
|
|
||||||
<div align="center" width="100%">
|
<div align="center" width="100%">
|
||||||
<img src="./public/icon.svg" width="128" alt="" />
|
<img src="./public/icon.svg" width="128" alt="" />
|
||||||
</div>
|
</div>
|
||||||
@@ -18,6 +21,7 @@ It is a self-hosted monitoring tool like "Uptime Robot".
|
|||||||
# How to Use
|
# How to Use
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create a volume
|
# Create a volume
|
||||||
docker volume create uptime-kuma
|
docker volume create uptime-kuma
|
||||||
@@ -70,11 +74,13 @@ Choose Cheapest Plan is enough. (US$ 5)
|
|||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
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
|
||||||
git fetch --all
|
git fetch --all
|
||||||
git checkout 1.0.2 --force
|
git checkout 1.0.5 --force
|
||||||
npm install
|
npm install
|
||||||
npm run build
|
npm run build
|
||||||
pm2 restart uptime-kuma
|
pm2 restart uptime-kuma
|
||||||
|
36
dockerfile
36
dockerfile
@@ -1,11 +1,30 @@
|
|||||||
FROM node:14-alpine3.14
|
# DON'T UPDATE TO alpine3.13, 1.14, see #41.
|
||||||
|
FROM node:14-alpine3.12 AS release
|
||||||
# sqlite have to build on arm
|
|
||||||
# TODO: use prebuilt sqlite for arm, because it is very very slow.
|
|
||||||
RUN apk add --no-cache make g++ python3
|
|
||||||
RUN ln -s /usr/bin/python3 /usr/bin/python
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
# split the sqlite install here, so that it can caches the arm prebuilt
|
||||||
|
RUN apk add --no-cache --virtual .build-deps make g++ python3 python3-dev && \
|
||||||
|
ln -s /usr/bin/python3 /usr/bin/python && \
|
||||||
|
npm install sqlite3@5.0.2 bcrypt@5.0.1 && \
|
||||||
|
apk del .build-deps
|
||||||
|
|
||||||
|
# Touching above code may causes sqlite3 re-compile again, painful slow.
|
||||||
|
|
||||||
|
# Install apprise
|
||||||
|
# Hate pip!!! I never run pip install successfully in first run for anything in my life without Google :/
|
||||||
|
# Compilation Fail 1 => Google Search "alpine ffi.h" => Add libffi-dev
|
||||||
|
# Compilation Fail 2 => Google Search "alpine cargo" => Add cargo
|
||||||
|
# Compilation Fail 3 => Google Search "alpine opensslv.h" => Add openssl-dev
|
||||||
|
# Compilation Fail 4 => Google Search "alpine opensslv.h" again => Change to libressl-dev musl-dev
|
||||||
|
# Compilation Fail 5 => Google Search "ERROR: libressl3.3-libtls-3.3.3-r0: trying to overwrite usr/lib/libtls.so.20 owned by libretls-3.3.3-r0." again => Change back to openssl-dev with musl-dev
|
||||||
|
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
|
||||||
|
RUN apk add --no-cache python3
|
||||||
|
RUN apk add --no-cache --virtual .build-deps libffi-dev musl-dev openssl-dev cargo py3-pip python3-dev && \
|
||||||
|
pip3 install apprise && \
|
||||||
|
apk del .build-deps
|
||||||
|
|
||||||
|
# New things add here
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm install
|
RUN npm install
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
@@ -13,3 +32,6 @@ RUN npm run build
|
|||||||
EXPOSE 3001
|
EXPOSE 3001
|
||||||
VOLUME ["/app/data"]
|
VOLUME ["/app/data"]
|
||||||
CMD ["npm", "run", "start-server"]
|
CMD ["npm", "run", "start-server"]
|
||||||
|
|
||||||
|
FROM release AS nightly
|
||||||
|
RUN npm run mark-as-nightly
|
||||||
|
39
extra/mark-as-nightly.js
Normal file
39
extra/mark-as-nightly.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* String.prototype.replaceAll() polyfill
|
||||||
|
* https://gomakethings.com/how-to-replace-a-section-of-a-string-with-another-one-with-vanilla-js/
|
||||||
|
* @author Chris Ferdinandi
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
if (!String.prototype.replaceAll) {
|
||||||
|
String.prototype.replaceAll = function(str, newStr){
|
||||||
|
|
||||||
|
// If a regex pattern
|
||||||
|
if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {
|
||||||
|
return this.replace(str, newStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a string
|
||||||
|
return this.replace(new RegExp(str, 'g'), newStr);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const pkg = require('../package.json');
|
||||||
|
const fs = require("fs");
|
||||||
|
const oldVersion = pkg.version
|
||||||
|
const newVersion = oldVersion + "-nightly"
|
||||||
|
|
||||||
|
console.log("Old Version: " + oldVersion)
|
||||||
|
console.log("New Version: " + newVersion)
|
||||||
|
|
||||||
|
if (newVersion) {
|
||||||
|
// Process package.json
|
||||||
|
pkg.version = newVersion
|
||||||
|
pkg.scripts.setup = pkg.scripts.setup.replaceAll(oldVersion, newVersion)
|
||||||
|
pkg.scripts["build-docker"] = pkg.scripts["build-docker"].replaceAll(oldVersion, newVersion)
|
||||||
|
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n")
|
||||||
|
|
||||||
|
// Process README.md
|
||||||
|
fs.writeFileSync("README.md", fs.readFileSync("README.md", 'utf8').replaceAll(oldVersion, newVersion))
|
||||||
|
}
|
||||||
|
|
@@ -3,6 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||||
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Uptime Kuma</title>
|
<title>Uptime Kuma</title>
|
||||||
</head>
|
</head>
|
||||||
|
11
package-lock.json
generated
11
package-lock.json
generated
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"requires": true,
|
"version": "1.0.4",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": {
|
"@babel/helper-validator-identifier": {
|
||||||
"version": "7.14.5",
|
"version": "7.14.5",
|
||||||
@@ -1518,6 +1519,14 @@
|
|||||||
"toidentifier": "1.0.0"
|
"toidentifier": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"http-graceful-shutdown": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-graceful-shutdown/-/http-graceful-shutdown-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-2vmU3kWOsZqZy4Kn4EZp00CF+6glpNNN/NAYJPkO9bnMX/D8sRl29TsxIu9Vgyo8ygtCWazWJp720zHfqhSdXg==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"http-signature": {
|
"http-signature": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||||
|
12
package.json
12
package.json
@@ -1,16 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.0.2",
|
"version": "1.0.5",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"start-server": "node server/server.js",
|
"start-server": "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.0.2 . --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.0.5 --target release . --push",
|
||||||
"build-docker-nightly": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly . --push",
|
"build-docker-nightly": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly --target nightly . --push",
|
||||||
"setup": "git checkout 1.0.2 && npm install && npm run build",
|
"setup": "git checkout 1.0.5 && npm install && npm run build",
|
||||||
"version-global-replace": "node extra/version-global-replace.js"
|
"version-global-replace": "node extra/version-global-replace.js",
|
||||||
|
"mark-as-nightly": "node extra/mark-as-nightly.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@popperjs/core": "^2.9.2",
|
"@popperjs/core": "^2.9.2",
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
|
"http-graceful-shutdown": "^3.1.2",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"nodemailer": "^6.6.2",
|
"nodemailer": "^6.6.2",
|
||||||
"password-hash": "^1.2.2",
|
"password-hash": "^1.2.2",
|
||||||
|
BIN
public/apple-touch-icon.png
Normal file
BIN
public/apple-touch-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
@@ -19,6 +19,22 @@ class Notification {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (notification.type === "gotify") {
|
||||||
|
try {
|
||||||
|
if (notification.gotifyserverurl.endsWith("/")) {
|
||||||
|
notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1);
|
||||||
|
}
|
||||||
|
await axios.post(`${notification.gotifyserverurl}/message?token=${notification.gotifyapplicationToken}`, {
|
||||||
|
"message": msg,
|
||||||
|
"priority": notification.gotifyPriority || 8,
|
||||||
|
"title": "Uptime-Kuma"
|
||||||
|
})
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (notification.type === "webhook") {
|
} else if (notification.type === "webhook") {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -92,7 +108,6 @@ class Notification {
|
|||||||
console.log(error)
|
console.log(error)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return await Notification.discord(notification, msg)
|
|
||||||
|
|
||||||
} else if (notification.type === "signal") {
|
} else if (notification.type === "signal") {
|
||||||
try {
|
try {
|
||||||
@@ -110,6 +125,58 @@ class Notification {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (notification.type === "slack") {
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let data = {'text': "Uptime Kuma Slack testing successful."}
|
||||||
|
let res = await axios.post(notification.slackwebhookURL, data)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = heartbeatJSON["time"];
|
||||||
|
let data = {
|
||||||
|
"blocks": [{
|
||||||
|
"type": "header",
|
||||||
|
"text": {
|
||||||
|
"type": "plain_text",
|
||||||
|
"text": "Uptime Kuma Alert"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "section",
|
||||||
|
"fields": [{
|
||||||
|
"type": "mrkdwn",
|
||||||
|
"text": '*Message*\n'+msg
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "mrkdwn",
|
||||||
|
"text": "*Time (UTC)*\n"+time
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "actions",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "button",
|
||||||
|
"text": {
|
||||||
|
"type": "plain_text",
|
||||||
|
"text": "Visit Uptime Kuma",
|
||||||
|
},
|
||||||
|
"value": "Uptime-Kuma",
|
||||||
|
"url": notification.slackbutton
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
let res = await axios.post(notification.slackwebhookURL, data)
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Notification type is not supported")
|
throw new Error("Notification type is not supported")
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
|
console.log("Welcome to Uptime Kuma ")
|
||||||
|
console.log("Importing libraries")
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const app = express();
|
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const server = http.createServer(app);
|
|
||||||
const { Server } = require("socket.io");
|
const { Server } = require("socket.io");
|
||||||
const io = new Server(server);
|
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const {R} = require("redbean-node");
|
const {R} = require("redbean-node");
|
||||||
const passwordHash = require('./password-hash');
|
const passwordHash = require('./password-hash');
|
||||||
@@ -12,12 +11,20 @@ const Monitor = require("./model/monitor");
|
|||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const {getSettings} = require("./util-server");
|
const {getSettings} = require("./util-server");
|
||||||
const {Notification} = require("./notification")
|
const {Notification} = require("./notification")
|
||||||
|
const gracefulShutdown = require('http-graceful-shutdown');
|
||||||
|
const {sleep} = require("./util");
|
||||||
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 = args.host || "0.0.0.0"
|
const hostname = args.host || "0.0.0.0"
|
||||||
const port = args.port || 3001
|
const port = args.port || 3001
|
||||||
|
|
||||||
|
console.log("Version: " + version)
|
||||||
|
|
||||||
|
console.log("Creating express and socket.io instance")
|
||||||
|
const app = express();
|
||||||
|
const server = http.createServer(app);
|
||||||
|
const io = new Server(server);
|
||||||
app.use(express.json())
|
app.use(express.json())
|
||||||
|
|
||||||
let totalClient = 0;
|
let totalClient = 0;
|
||||||
@@ -539,11 +546,11 @@ async function initDatabase() {
|
|||||||
const path = './data/kuma.db';
|
const path = './data/kuma.db';
|
||||||
|
|
||||||
if (! fs.existsSync(path)) {
|
if (! fs.existsSync(path)) {
|
||||||
console.log("Copy Database")
|
console.log("Copying Database")
|
||||||
fs.copyFileSync("./db/kuma.db", path);
|
fs.copyFileSync("./db/kuma.db", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Connect to Database")
|
console.log("Connecting to Database")
|
||||||
|
|
||||||
R.setup('sqlite', {
|
R.setup('sqlite', {
|
||||||
filename: path
|
filename: path
|
||||||
@@ -660,3 +667,72 @@ async function sendImportantHeartbeatList(socket, monitorID) {
|
|||||||
|
|
||||||
socket.emit("importantHeartbeatList", monitorID, list)
|
socket.emit("importantHeartbeatList", monitorID, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const startGracefulShutdown = async () => {
|
||||||
|
console.log('Shutdown requested');
|
||||||
|
|
||||||
|
|
||||||
|
await (new Promise((resolve) => {
|
||||||
|
server.close(async function () {
|
||||||
|
console.log('Stopped Express.');
|
||||||
|
process.exit(0)
|
||||||
|
setTimeout(async () =>{
|
||||||
|
await R.close();
|
||||||
|
console.log("Stopped DB")
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
}, 5000)
|
||||||
|
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let noReject = true;
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
noReject = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function shutdownFunction(signal) {
|
||||||
|
console.log('Called signal: ' + signal);
|
||||||
|
|
||||||
|
console.log("Stopping all monitors")
|
||||||
|
for (let id in monitorList) {
|
||||||
|
let monitor = monitorList[id]
|
||||||
|
monitor.stop()
|
||||||
|
}
|
||||||
|
await sleep(2000)
|
||||||
|
|
||||||
|
console.log("Closing DB")
|
||||||
|
|
||||||
|
// Special handle, because tarn.js throw a promise reject that cannot be caught
|
||||||
|
while (true) {
|
||||||
|
noReject = true;
|
||||||
|
await R.close()
|
||||||
|
await sleep(2000)
|
||||||
|
|
||||||
|
if (noReject) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
console.log("Waiting...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("OK")
|
||||||
|
}
|
||||||
|
|
||||||
|
function finalFunction() {
|
||||||
|
console.log('Graceful Shutdown')
|
||||||
|
}
|
||||||
|
|
||||||
|
gracefulShutdown(server, {
|
||||||
|
signals: 'SIGINT SIGTERM',
|
||||||
|
timeout: 30000, // timeout: 30 secs
|
||||||
|
development: false, // not in dev mode
|
||||||
|
forceExit: true, // triggers process.exit() at the end of shutdown process
|
||||||
|
onShutdown: shutdownFunction, // shutdown function (async) - e.g. for cleanup DB, ...
|
||||||
|
finally: finalFunction // finally function (sync) - e.g. for logging
|
||||||
|
});
|
||||||
|
@@ -1,15 +1,11 @@
|
|||||||
/*
|
// Common JS cannot be used in frontend sadly
|
||||||
* Common functions - can be used in frontend or backend
|
// sleep, ucfirst is duplicated in ../src/util-frontend.js
|
||||||
*/
|
|
||||||
|
|
||||||
|
exports.sleep = function (ms) {
|
||||||
|
|
||||||
|
|
||||||
export function sleep(ms) {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms));
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ucfirst(str) {
|
exports.ucfirst = function (str) {
|
||||||
if (! str) {
|
if (! str) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import {sleep} from "../../server/util";
|
import {sleep} from '../util-frontend'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
||||||
|
@@ -18,6 +18,8 @@
|
|||||||
<option value="smtp">Email (SMTP)</option>
|
<option value="smtp">Email (SMTP)</option>
|
||||||
<option value="discord">Discord</option>
|
<option value="discord">Discord</option>
|
||||||
<option value="signal">Signal</option>
|
<option value="signal">Signal</option>
|
||||||
|
<option value="gotify">Gotify</option>
|
||||||
|
<option value="slack">Slack</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -169,6 +171,38 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template v-if="notification.type === 'gotify'">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gotify-application-token" class="form-label">Application Token</label>
|
||||||
|
<input type="text" class="form-control" id="gotify-application-token" required v-model="notification.gotifyapplicationToken">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gotify-server-url" class="form-label">Server URL</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="text" class="form-control" id="gotify-server-url" required v-model="notification.gotifyserverurl">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="gotify-priority" class="form-label">Priority</label>
|
||||||
|
<input type="number" class="form-control" id="gotify-priority" v-model="notification.gotifyPriority" required min="0" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="notification.type === 'slack'">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="slack-webhook-url" class="form-label">Slack Webhook URL</label>
|
||||||
|
<input type="text" class="form-control" id="slack-webhook-url" required v-model="notification.slackwebhookURL" autocomplete="false">
|
||||||
|
<label for="gotify-server-url" class="form-label">Uptime Kuma URL</label>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="text" class="form-control" id="slack-button" required v-model="notification.slackbutton" autocomplete="false">
|
||||||
|
</div>
|
||||||
|
<p style="margin-top: 8px;">
|
||||||
|
More info on: <a href="https://api.slack.com/messaging/webhooks" target="_blank">https://api.slack.com/messaging/webhooks</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-danger" @click="deleteConfirm" :disabled="processing" v-if="id">Delete</button>
|
<button type="button" class="btn btn-danger" @click="deleteConfirm" :disabled="processing" v-if="id">Delete</button>
|
||||||
@@ -186,7 +220,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Modal } from 'bootstrap'
|
import { Modal } from 'bootstrap'
|
||||||
import { ucfirst } from "../../server/util";
|
import { ucfirst } from '../util-frontend'
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useToast } from 'vue-toastification'
|
import { useToast } from 'vue-toastification'
|
||||||
import Confirm from "./Confirm.vue";
|
import Confirm from "./Confirm.vue";
|
||||||
@@ -205,6 +239,7 @@ export default {
|
|||||||
notification: {
|
notification: {
|
||||||
name: "",
|
name: "",
|
||||||
type: null,
|
type: null,
|
||||||
|
gotifyPriority: 8
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -244,6 +279,7 @@ export default {
|
|||||||
|
|
||||||
// Default set to Telegram
|
// Default set to Telegram
|
||||||
this.notification.type = "telegram"
|
this.notification.type = "telegram"
|
||||||
|
this.notification.gotifyPriority = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modal.show()
|
this.modal.show()
|
||||||
|
@@ -5,6 +5,19 @@ import timezone from 'dayjs/plugin/timezone'
|
|||||||
dayjs.extend(utc)
|
dayjs.extend(utc)
|
||||||
dayjs.extend(timezone)
|
dayjs.extend(timezone)
|
||||||
|
|
||||||
|
export function sleep(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ucfirst(str) {
|
||||||
|
if (! str) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstLetter = str.substr(0, 1);
|
||||||
|
return firstLetter.toUpperCase() + str.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function getTimezoneOffset(timeZone) {
|
function getTimezoneOffset(timeZone) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
Reference in New Issue
Block a user