commit
e683033f4e
Binary file not shown.
@ -0,0 +1,10 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
-- For sendHeartbeatList
|
||||||
|
CREATE INDEX monitor_time_index ON heartbeat (monitor_id, time);
|
||||||
|
|
||||||
|
-- For sendImportantHeartbeatList
|
||||||
|
CREATE INDEX monitor_important_time_index ON heartbeat (monitor_id, important,time);
|
||||||
|
|
||||||
|
COMMIT;
|
@ -0,0 +1,7 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE notification
|
||||||
|
ADD is_default BOOLEAN default 0 NOT NULL;
|
||||||
|
|
||||||
|
COMMIT;
|
@ -0,0 +1,26 @@
|
|||||||
|
# DON'T UPDATE TO alpine3.13, 1.14, see #41.
|
||||||
|
FROM node:14-alpine3.12 AS release
|
||||||
|
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 git && \
|
||||||
|
ln -s /usr/bin/python3 /usr/bin/python && \
|
||||||
|
npm install mapbox/node-sqlite3#593c9d && \
|
||||||
|
apk del .build-deps && \
|
||||||
|
rm -f /usr/bin/python
|
||||||
|
|
||||||
|
# Install apprise
|
||||||
|
RUN apk add --no-cache python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib
|
||||||
|
RUN pip3 --no-cache-dir install apprise && \
|
||||||
|
rm -rf /root/.cache
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN npm install --legacy-peer-deps && npm run build && npm prune
|
||||||
|
|
||||||
|
EXPOSE 3001
|
||||||
|
VOLUME ["/app/data"]
|
||||||
|
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js
|
||||||
|
CMD ["node", "server/server.js"]
|
||||||
|
|
||||||
|
FROM release AS nightly
|
||||||
|
RUN npm run mark-as-nightly
|
@ -1,19 +1,31 @@
|
|||||||
let http = require("http");
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
|
|
||||||
|
let client;
|
||||||
|
|
||||||
|
if (process.env.SSL_KEY && process.env.SSL_CERT) {
|
||||||
|
client = require("https");
|
||||||
|
} else {
|
||||||
|
client = require("http");
|
||||||
|
}
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
host: "localhost",
|
host: process.env.HOST || "127.0.0.1",
|
||||||
port: "3001",
|
port: parseInt(process.env.PORT) || 3001,
|
||||||
timeout: 2000,
|
timeout: 28 * 1000,
|
||||||
};
|
};
|
||||||
let request = http.request(options, (res) => {
|
|
||||||
console.log(`STATUS: ${res.statusCode}`);
|
let request = client.request(options, (res) => {
|
||||||
if (res.statusCode == 200) {
|
console.log(`Health Check OK [Res Code: ${res.statusCode}]`);
|
||||||
|
if (res.statusCode === 200) {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
request.on("error", function (err) {
|
request.on("error", function (err) {
|
||||||
console.log("ERROR");
|
console.error("Health Check ERROR");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
request.end();
|
request.end();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* For Client Socket
|
||||||
|
*/
|
||||||
|
const { TimeLogger } = require("../src/util");
|
||||||
|
const { R } = require("redbean-node");
|
||||||
|
const { io } = require("./server");
|
||||||
|
|
||||||
|
async function sendNotificationList(socket) {
|
||||||
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
let list = await R.find("notification", " user_id = ? ", [
|
||||||
|
socket.userID,
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (let bean of list) {
|
||||||
|
result.push(bean.export())
|
||||||
|
}
|
||||||
|
|
||||||
|
io.to(socket.userID).emit("notificationList", result)
|
||||||
|
|
||||||
|
timeLogger.print("Send Notification List");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send Heartbeat History list to socket
|
||||||
|
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only
|
||||||
|
* @param overwrite Overwrite client-side's heartbeat list
|
||||||
|
*/
|
||||||
|
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
|
let list = await R.getAll(`
|
||||||
|
SELECT * FROM heartbeat
|
||||||
|
WHERE monitor_id = ?
|
||||||
|
ORDER BY time DESC
|
||||||
|
LIMIT 100
|
||||||
|
`, [
|
||||||
|
monitorID,
|
||||||
|
])
|
||||||
|
|
||||||
|
let result = list.reverse();
|
||||||
|
|
||||||
|
if (toUser) {
|
||||||
|
io.to(socket.userID).emit("heartbeatList", monitorID, result, overwrite);
|
||||||
|
} else {
|
||||||
|
socket.emit("heartbeatList", monitorID, result, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
timeLogger.print(`[Monitor: ${monitorID}] sendHeartbeatList`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Important Heart beat list (aka event list)
|
||||||
|
* @param socket
|
||||||
|
* @param monitorID
|
||||||
|
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only
|
||||||
|
* @param overwrite Overwrite client-side's heartbeat list
|
||||||
|
*/
|
||||||
|
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
|
||||||
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
|
let list = await R.find("heartbeat", `
|
||||||
|
monitor_id = ?
|
||||||
|
AND important = 1
|
||||||
|
ORDER BY time DESC
|
||||||
|
LIMIT 500
|
||||||
|
`, [
|
||||||
|
monitorID,
|
||||||
|
])
|
||||||
|
|
||||||
|
timeLogger.print(`[Monitor: ${monitorID}] sendImportantHeartbeatList`);
|
||||||
|
|
||||||
|
if (toUser) {
|
||||||
|
io.to(socket.userID).emit("importantHeartbeatList", monitorID, list, overwrite);
|
||||||
|
} else {
|
||||||
|
socket.emit("importantHeartbeatList", monitorID, list, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
sendNotificationList,
|
||||||
|
sendImportantHeartbeatList,
|
||||||
|
sendHeartbeatList,
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const child_process = require("child_process");
|
||||||
|
|
||||||
|
class Apprise extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "apprise";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL])
|
||||||
|
|
||||||
|
let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
|
||||||
|
if (! output.includes("ERROR")) {
|
||||||
|
return "Sent Successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(output)
|
||||||
|
} else {
|
||||||
|
return "No output from apprise";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Apprise;
|
@ -0,0 +1,105 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Discord extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "discord";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const discordDisplayName = notification.discordUsername || "Uptime Kuma";
|
||||||
|
|
||||||
|
// If heartbeatJSON is null, assume we're testing.
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let discordtestdata = {
|
||||||
|
username: discordDisplayName,
|
||||||
|
content: msg,
|
||||||
|
}
|
||||||
|
await axios.post(notification.discordWebhookUrl, discordtestdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (monitorJSON["type"] === "port") {
|
||||||
|
url = monitorJSON["hostname"];
|
||||||
|
if (monitorJSON["port"]) {
|
||||||
|
url += ":" + monitorJSON["port"];
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
url = monitorJSON["url"];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let discorddowndata = {
|
||||||
|
username: discordDisplayName,
|
||||||
|
embeds: [{
|
||||||
|
title: "❌ Your service " + monitorJSON["name"] + " went down. ❌",
|
||||||
|
color: 16711680,
|
||||||
|
timestamp: heartbeatJSON["time"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Service URL",
|
||||||
|
value: url,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Error",
|
||||||
|
value: heartbeatJSON["msg"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
await axios.post(notification.discordWebhookUrl, discorddowndata)
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
let discordupdata = {
|
||||||
|
username: discordDisplayName,
|
||||||
|
embeds: [{
|
||||||
|
title: "✅ Your service " + monitorJSON["name"] + " is up! ✅",
|
||||||
|
color: 65280,
|
||||||
|
timestamp: heartbeatJSON["time"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Service URL",
|
||||||
|
value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ping",
|
||||||
|
value: heartbeatJSON["ping"] + "ms",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
await axios.post(notification.discordWebhookUrl, discordupdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Discord;
|
@ -0,0 +1,28 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Gotify extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "gotify";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
if (notification.gotifyserverurl && 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 okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Gotify;
|
@ -0,0 +1,60 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Line extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "line";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
let lineAPIUrl = "https://api.line.me/v2/bot/message/push";
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": "Bearer " + notification.lineChannelAccessToken
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let testMessage = {
|
||||||
|
"to": notification.lineUserID,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "Test Successful!"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(lineAPIUrl, testMessage, config)
|
||||||
|
} else if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let downMessage = {
|
||||||
|
"to": notification.lineUserID,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(lineAPIUrl, downMessage, config)
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
let upMessage = {
|
||||||
|
"to": notification.lineUserID,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(lineAPIUrl, upMessage, config)
|
||||||
|
}
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Line;
|
@ -0,0 +1,48 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class LunaSea extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "lunasea";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let testdata = {
|
||||||
|
"title": "Uptime Kuma Alert",
|
||||||
|
"body": "Testing Successful.",
|
||||||
|
}
|
||||||
|
await axios.post(lunaseadevice, testdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let downdata = {
|
||||||
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
|
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
|
}
|
||||||
|
await axios.post(lunaseadevice, downdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == UP) {
|
||||||
|
let updata = {
|
||||||
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
|
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
|
}
|
||||||
|
await axios.post(lunaseadevice, updata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LunaSea;
|
@ -0,0 +1,123 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Mattermost extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "mattermost";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
|
||||||
|
// If heartbeatJSON is null, assume we're testing.
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let mattermostTestData = {
|
||||||
|
username: mattermostUserName,
|
||||||
|
text: msg,
|
||||||
|
}
|
||||||
|
await axios.post(notification.mattermostWebhookUrl, mattermostTestData)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mattermostChannel = notification.mattermostchannel;
|
||||||
|
const mattermostIconEmoji = notification.mattermosticonemo;
|
||||||
|
const mattermostIconUrl = notification.mattermosticonurl;
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let mattermostdowndata = {
|
||||||
|
username: mattermostUserName,
|
||||||
|
text: "Uptime Kuma Alert",
|
||||||
|
channel: mattermostChannel,
|
||||||
|
icon_emoji: mattermostIconEmoji,
|
||||||
|
icon_url: mattermostIconUrl,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
fallback:
|
||||||
|
"Your " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went down.",
|
||||||
|
color: "#FF0000",
|
||||||
|
title:
|
||||||
|
"❌ " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went down. ❌",
|
||||||
|
title_link: monitorJSON["url"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: false,
|
||||||
|
title: "Error",
|
||||||
|
value: heartbeatJSON["msg"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
await axios.post(
|
||||||
|
notification.mattermostWebhookUrl,
|
||||||
|
mattermostdowndata
|
||||||
|
);
|
||||||
|
return okMsg;
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
let mattermostupdata = {
|
||||||
|
username: mattermostUserName,
|
||||||
|
text: "Uptime Kuma Alert",
|
||||||
|
channel: mattermostChannel,
|
||||||
|
icon_emoji: mattermostIconEmoji,
|
||||||
|
icon_url: mattermostIconUrl,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
fallback:
|
||||||
|
"Your " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went up!",
|
||||||
|
color: "#32CD32",
|
||||||
|
title:
|
||||||
|
"✅ " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went up! ✅",
|
||||||
|
title_link: monitorJSON["url"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: false,
|
||||||
|
title: "Ping",
|
||||||
|
value: heartbeatJSON["ping"] + "ms",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
await axios.post(
|
||||||
|
notification.mattermostWebhookUrl,
|
||||||
|
mattermostupdata
|
||||||
|
);
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Mattermost;
|
@ -0,0 +1,36 @@
|
|||||||
|
class NotificationProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification Provider Name
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
name = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param notification : BeanModel
|
||||||
|
* @param msg : string General Message
|
||||||
|
* @param monitorJSON : object Monitor details (For Up/Down only)
|
||||||
|
* @param heartbeatJSON : object Heartbeat details (For Up/Down only)
|
||||||
|
* @returns {Promise<string>} Return Successful Message
|
||||||
|
* Throw Error with fail msg
|
||||||
|
*/
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
throw new Error("Have to override Notification.send(...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
throwGeneralAxiosError(error) {
|
||||||
|
let msg = "Error: " + error + " ";
|
||||||
|
|
||||||
|
if (error.response && error.response.data) {
|
||||||
|
if (typeof error.response.data === "string") {
|
||||||
|
msg += error.response.data;
|
||||||
|
} else {
|
||||||
|
msg += JSON.stringify(error.response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = NotificationProvider;
|
@ -0,0 +1,40 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Octopush extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "octopush";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
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 okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Octopush;
|
@ -0,0 +1,50 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Pushbullet extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "pushbullet";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
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"] == DOWN) {
|
||||||
|
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"] == UP) {
|
||||||
|
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) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Pushbullet;
|
@ -0,0 +1,49 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Pushover extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "pushover";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
let pushoverlink = "https://api.pushover.net/1/messages.json"
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let data = {
|
||||||
|
"message": "<b>Uptime Kuma Pushover testing successful.</b>",
|
||||||
|
"user": notification.pushoveruserkey,
|
||||||
|
"token": notification.pushoverapptoken,
|
||||||
|
"sound": notification.pushoversounds,
|
||||||
|
"priority": notification.pushoverpriority,
|
||||||
|
"title": notification.pushovertitle,
|
||||||
|
"retry": "30",
|
||||||
|
"expire": "3600",
|
||||||
|
"html": 1,
|
||||||
|
}
|
||||||
|
await axios.post(pushoverlink, data)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
"message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" + msg + "\n<b>Time (UTC)</b>:" + heartbeatJSON["time"],
|
||||||
|
"user": notification.pushoveruserkey,
|
||||||
|
"token": notification.pushoverapptoken,
|
||||||
|
"sound": notification.pushoversounds,
|
||||||
|
"priority": notification.pushoverpriority,
|
||||||
|
"title": notification.pushovertitle,
|
||||||
|
"retry": "30",
|
||||||
|
"expire": "3600",
|
||||||
|
"html": 1,
|
||||||
|
}
|
||||||
|
await axios.post(pushoverlink, data)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Pushover;
|
@ -0,0 +1,30 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Pushy extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "pushy";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, {
|
||||||
|
"to": notification.pushyToken,
|
||||||
|
"data": {
|
||||||
|
"message": "Uptime-Kuma"
|
||||||
|
},
|
||||||
|
"notification": {
|
||||||
|
"body": msg,
|
||||||
|
"badge": 1,
|
||||||
|
"sound": "ping.aiff"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Pushy;
|
@ -0,0 +1,46 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class RocketChat extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "rocket.chat";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Rocket.chat testing successful.",
|
||||||
|
"channel": notification.rocketchannel,
|
||||||
|
"username": notification.rocketusername,
|
||||||
|
"icon_emoji": notification.rocketiconemo,
|
||||||
|
}
|
||||||
|
await axios.post(notification.rocketwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = heartbeatJSON["time"];
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Alert",
|
||||||
|
"channel": notification.rocketchannel,
|
||||||
|
"username": notification.rocketusername,
|
||||||
|
"icon_emoji": notification.rocketiconemo,
|
||||||
|
"attachments": [
|
||||||
|
{
|
||||||
|
"title": "Uptime Kuma Alert *Time (UTC)*\n" + time,
|
||||||
|
"title_link": notification.rocketbutton,
|
||||||
|
"text": "*Message*\n" + msg,
|
||||||
|
"color": "#32cd32"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(notification.rocketwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = RocketChat;
|
@ -0,0 +1,27 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Signal extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "signal";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
"message": msg,
|
||||||
|
"number": notification.signalNumber,
|
||||||
|
"recipients": notification.signalRecipients.replace(/\s/g, "").split(","),
|
||||||
|
};
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
await axios.post(notification.signalURL, data, config)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Signal;
|
@ -0,0 +1,70 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Slack extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "slack";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Slack testing successful.",
|
||||||
|
"channel": notification.slackchannel,
|
||||||
|
"username": notification.slackusername,
|
||||||
|
"icon_emoji": notification.slackiconemo,
|
||||||
|
}
|
||||||
|
await axios.post(notification.slackwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = heartbeatJSON["time"];
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Alert",
|
||||||
|
"channel": notification.slackchannel,
|
||||||
|
"username": notification.slackusername,
|
||||||
|
"icon_emoji": notification.slackiconemo,
|
||||||
|
"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 || "https://github.com/louislam/uptime-kuma",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
await axios.post(notification.slackwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Slack;
|
@ -0,0 +1,48 @@
|
|||||||
|
const nodemailer = require("nodemailer");
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
|
||||||
|
class SMTP extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "smtp";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
host: notification.smtpHost,
|
||||||
|
port: notification.smtpPort,
|
||||||
|
secure: notification.smtpSecure,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
|
||||||
|
if (notification.smtpUsername || notification.smtpPassword) {
|
||||||
|
config.auth = {
|
||||||
|
user: notification.smtpUsername,
|
||||||
|
pass: notification.smtpPassword,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let transporter = nodemailer.createTransport(config);
|
||||||
|
|
||||||
|
let bodyTextContent = msg;
|
||||||
|
if (heartbeatJSON) {
|
||||||
|
bodyTextContent = `${msg}\nTime (UTC): ${heartbeatJSON["time"]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send mail with defined transport object
|
||||||
|
await transporter.sendMail({
|
||||||
|
from: notification.smtpFrom,
|
||||||
|
cc: notification.smtpCC,
|
||||||
|
bcc: notification.smtpBCC,
|
||||||
|
to: notification.smtpTo,
|
||||||
|
subject: msg,
|
||||||
|
text: bodyTextContent,
|
||||||
|
tls: {
|
||||||
|
rejectUnauthorized: notification.smtpIgnoreTLSError || false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return "Sent Successfully.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SMTP;
|
@ -0,0 +1,27 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Telegram extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "telegram";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
||||||
|
params: {
|
||||||
|
chat_id: notification.telegramChatID,
|
||||||
|
text: msg,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
let msg = (error.response.data.description) ? error.response.data.description : "Error without description"
|
||||||
|
throw new Error(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Telegram;
|
@ -0,0 +1,44 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const FormData = require("form-data");
|
||||||
|
|
||||||
|
class Webhook extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "webhook";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
heartbeat: heartbeatJSON,
|
||||||
|
monitor: monitorJSON,
|
||||||
|
msg,
|
||||||
|
};
|
||||||
|
let finalData;
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
if (notification.webhookContentType === "form-data") {
|
||||||
|
finalData = new FormData();
|
||||||
|
finalData.append("data", JSON.stringify(data));
|
||||||
|
|
||||||
|
config = {
|
||||||
|
headers: finalData.getHeaders(),
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
finalData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.post(notification.webhookURL, finalData, config)
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Webhook;
|
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input
|
||||||
|
ref="input"
|
||||||
|
v-model="model"
|
||||||
|
:type="visibility"
|
||||||
|
class="form-control"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:autocomplete="autocomplete"
|
||||||
|
:required="required"
|
||||||
|
:readonly="readonly"
|
||||||
|
>
|
||||||
|
|
||||||
|
<a v-if="visibility == 'password'" class="btn btn-outline-primary" @click="showInput()">
|
||||||
|
<font-awesome-icon icon="eye" />
|
||||||
|
</a>
|
||||||
|
<a v-if="visibility == 'text'" class="btn btn-outline-primary" @click="hideInput()">
|
||||||
|
<font-awesome-icon icon="eye-slash" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: Number,
|
||||||
|
default: 255
|
||||||
|
},
|
||||||
|
autocomplete: {
|
||||||
|
type: String,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
required: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
readonly: {
|
||||||
|
type: String,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visibility: "password",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
model: {
|
||||||
|
get() {
|
||||||
|
return this.modelValue
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.$emit("update:modelValue", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showInput() {
|
||||||
|
this.visibility = "text";
|
||||||
|
},
|
||||||
|
hideInput() {
|
||||||
|
this.visibility = "password";
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="hostname" class="form-label">{{ $t("Hostname") }}</label>
|
||||||
|
<input id="hostname" v-model="$parent.notification.smtpHost" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="port" class="form-label">{{ $t("Port") }}</label>
|
||||||
|
<input id="port" v-model="$parent.notification.smtpPort" type="number" class="form-control" required min="0" max="65535" step="1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="secure" class="form-label">Secure</label>
|
||||||
|
<select id="secure" v-model="$parent.notification.smtpSecure" class="form-select">
|
||||||
|
<option :value="false">None / STARTTLS (25, 587)</option>
|
||||||
|
<option :value="true">TLS (465)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="form-check">
|
||||||
|
<input id="ignore-tls-error" v-model="$parent.notification.smtpIgnoreTLSError" class="form-check-input" type="checkbox" value="">
|
||||||
|
<label class="form-check-label" for="ignore-tls-error">
|
||||||
|
Ignore TLS Error
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">{{ $t("Username") }}</label>
|
||||||
|
<input id="username" v-model="$parent.notification.smtpUsername" type="text" class="form-control" autocomplete="false">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">{{ $t("Password") }}</label>
|
||||||
|
<HiddenInput id="password" v-model="$parent.notification.smtpPassword" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="from-email" class="form-label">From Email</label>
|
||||||
|
<input id="from-email" v-model="$parent.notification.smtpFrom" type="text" class="form-control" required autocomplete="false" placeholder=""Uptime Kuma" <example@kuma.pet>">
|
||||||
|
<div class="form-text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="to-email" class="form-label">To Email</label>
|
||||||
|
<input id="to-email" v-model="$parent.notification.smtpTo" type="text" class="form-control" required autocomplete="false" placeholder="example2@kuma.pet, example3@kuma.pet">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="to-cc" class="form-label">CC</label>
|
||||||
|
<input id="to-cc" v-model="$parent.notification.smtpCC" type="text" class="form-control" autocomplete="false">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="to-bcc" class="form-label">BCC</label>
|
||||||
|
<input id="to-bcc" v-model="$parent.notification.smtpBCC" type="text" class="form-control" autocomplete="false">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HiddenInput from "../HiddenInput.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HiddenInput,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: "smtp",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,96 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="telegram-bot-token" class="form-label">Bot Token</label>
|
||||||
|
<HiddenInput id="telegram-bot-token" v-model="$parent.notification.telegramBotToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
|
<div class="form-text">
|
||||||
|
You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="telegram-chat-id" class="form-label">Chat ID</label>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input id="telegram-chat-id" v-model="$parent.notification.telegramChatID" type="text" class="form-control" required>
|
||||||
|
<button v-if="$parent.notification.telegramBotToken" class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID">
|
||||||
|
{{ $t("Auto Get") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-text">
|
||||||
|
Support Direct Chat / Group / Channel's Chat ID
|
||||||
|
|
||||||
|
<p style="margin-top: 8px;">
|
||||||
|
You can get your chat id by sending message to the bot and go to this url to view the chat_id:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p style="margin-top: 8px;">
|
||||||
|
<template v-if="$parent.notification.telegramBotToken">
|
||||||
|
<a :href="telegramGetUpdatesURL" target="_blank" style="word-break: break-word;">{{ telegramGetUpdatesURL }}</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
{{ telegramGetUpdatesURL }}
|
||||||
|
</template>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HiddenInput from "../HiddenInput.vue";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useToast } from "vue-toastification"
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HiddenInput,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: "telegram",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
telegramGetUpdatesURL() {
|
||||||
|
let token = "<YOUR BOT TOKEN HERE>"
|
||||||
|
|
||||||
|
if (this.$parent.notification.telegramBotToken) {
|
||||||
|
token = this.$parent.notification.telegramBotToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `https://api.telegram.org/bot${token}/getUpdates`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async autoGetTelegramChatID() {
|
||||||
|
try {
|
||||||
|
let res = await axios.get(this.telegramGetUpdatesURL)
|
||||||
|
|
||||||
|
if (res.data.result.length >= 1) {
|
||||||
|
let update = res.data.result[res.data.result.length - 1]
|
||||||
|
|
||||||
|
if (update.channel_post) {
|
||||||
|
this.notification.telegramChatID = update.channel_post.chat.id;
|
||||||
|
} else if (update.message) {
|
||||||
|
this.notification.telegramChatID = update.message.chat.id;
|
||||||
|
} else {
|
||||||
|
throw new Error("Chat ID is not found, please send a message to this bot first")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error("Chat ID is not found, please send a message to this bot first")
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,10 +1,10 @@
|
|||||||
import { library } from "@fortawesome/fontawesome-svg-core"
|
import { library } from "@fortawesome/fontawesome-svg-core"
|
||||||
import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp } from "@fortawesome/free-solid-svg-icons"
|
import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons"
|
||||||
//import { fa } from '@fortawesome/free-regular-svg-icons'
|
//import { fa } from '@fortawesome/free-regular-svg-icons'
|
||||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"
|
||||||
|
|
||||||
// Add Free Font Awesome Icons here
|
// Add Free Font Awesome Icons here
|
||||||
// https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free
|
// https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free
|
||||||
library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp);
|
library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash);
|
||||||
|
|
||||||
export { FontAwesomeIcon }
|
export { FontAwesomeIcon }
|
||||||
|
@ -0,0 +1,131 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Español",
|
||||||
|
checkEverySecond: "Comprobar cada {0} segundos.",
|
||||||
|
"Avg.": "Media. ",
|
||||||
|
retriesDescription: "Número máximo de intentos antes de que el servicio se marque como CAÍDO y una notificación sea enviada.",
|
||||||
|
ignoreTLSError: "Ignorar error TLS/SSL para sitios web HTTPS",
|
||||||
|
upsideDownModeDescription: "Invertir el estado. Si el servicio es alcanzable, está CAÍDO.",
|
||||||
|
maxRedirectDescription: "Número máximo de direcciones a seguir. Establecer a 0 para deshabilitar.",
|
||||||
|
acceptedStatusCodesDescription: "Seleccionar los códigos de estado que se consideran como respuesta exitosa.",
|
||||||
|
passwordNotMatchMsg: "La contraseña repetida no coincide.",
|
||||||
|
notificationDescription: "Por favor asigne una notificación a el/los monitor(es) para hacerlos funcional(es).",
|
||||||
|
keywordDescription: "Palabra clave en HTML plano o respuesta JSON y es sensible a mayúsculas",
|
||||||
|
pauseDashboardHome: "Pausar",
|
||||||
|
deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?",
|
||||||
|
deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?",
|
||||||
|
resoverserverDescription: "Cloudflare es el servidor por defecto, puedes cambiar el servidor de resolución en cualquier momento.",
|
||||||
|
rrtypeDescription: "Selecciona el tipo de registro que quieres monitorizar",
|
||||||
|
pauseMonitorMsg: "¿Seguro que quieres pausar?",
|
||||||
|
Settings: "Ajustes",
|
||||||
|
Dashboard: "Panel",
|
||||||
|
"New Update": "Vueva actualización",
|
||||||
|
Language: "Idioma",
|
||||||
|
Appearance: "Apariencia",
|
||||||
|
Theme: "Tema",
|
||||||
|
General: "General",
|
||||||
|
Version: "Versión",
|
||||||
|
"Check Update On GitHub": "Comprobar actualizaciones en GitHub",
|
||||||
|
List: "Lista",
|
||||||
|
Add: "Añadir",
|
||||||
|
"Add New Monitor": "Añadir nuevo monitor",
|
||||||
|
"Quick Stats": "Estadísticas rápidas",
|
||||||
|
Up: "Funcional",
|
||||||
|
Down: "Caído",
|
||||||
|
Pending: "Pendiente",
|
||||||
|
Unknown: "Desconociso",
|
||||||
|
Pause: "Pausa",
|
||||||
|
Name: "Nombre",
|
||||||
|
Status: "Estado",
|
||||||
|
DateTime: "Fecha y Hora",
|
||||||
|
Message: "Mensaje",
|
||||||
|
"No important events": "No hay eventos importantes",
|
||||||
|
Resume: "Reanudar",
|
||||||
|
Edit: "Editar",
|
||||||
|
Delete: "Eliminar",
|
||||||
|
Current: "Actual",
|
||||||
|
Uptime: "Tiempo activo",
|
||||||
|
"Cert Exp.": "Caducidad cert.",
|
||||||
|
days: "días",
|
||||||
|
day: "día",
|
||||||
|
"-day": "-día",
|
||||||
|
hour: "hora",
|
||||||
|
"-hour": "-hora",
|
||||||
|
Response: "Respuesta",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Tipo de Monitor",
|
||||||
|
Keyword: "Palabra clave",
|
||||||
|
"Friendly Name": "Nombre sencillo",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Nombre del host",
|
||||||
|
Port: "Puerto",
|
||||||
|
"Heartbeat Interval": "Intervalo de latido",
|
||||||
|
Retries: "Reintentos",
|
||||||
|
Advanced: "Avanzado",
|
||||||
|
"Upside Down Mode": "Modo invertido",
|
||||||
|
"Max. Redirects": "Máx. redirecciones",
|
||||||
|
"Accepted Status Codes": "Códigos de estado aceptados",
|
||||||
|
Save: "Guardar",
|
||||||
|
Notifications: "Notificaciones",
|
||||||
|
"Not available, please setup.": "No disponible, por favor configurar.",
|
||||||
|
"Setup Notification": "Configurar notificación",
|
||||||
|
Light: "Claro",
|
||||||
|
Dark: "Oscuro",
|
||||||
|
Auto: "Auto",
|
||||||
|
"Theme - Heartbeat Bar": "Tema - Barra de intervalo de latido",
|
||||||
|
Normal: "Normal",
|
||||||
|
Bottom: "Abajo",
|
||||||
|
None: "Ninguno",
|
||||||
|
Timezone: "Zona horaria",
|
||||||
|
"Search Engine Visibility": "Visibilidad motor de búsqueda",
|
||||||
|
"Allow indexing": "Permitir indexación",
|
||||||
|
"Discourage search engines from indexing site": "Disuadir a los motores de búsqueda de indexar el sitio",
|
||||||
|
"Change Password": "Cambiar contraseña",
|
||||||
|
"Current Password": "Contraseña actual",
|
||||||
|
"New Password": "Nueva contraseña",
|
||||||
|
"Repeat New Password": "Repetir nueva contraseña",
|
||||||
|
"Update Password": "Actualizar contraseña",
|
||||||
|
"Disable Auth": "Deshabilitar Autenticación ",
|
||||||
|
"Enable Auth": "Habilitar Autenticación ",
|
||||||
|
Logout: "Cerrar sesión",
|
||||||
|
Leave: "Salir",
|
||||||
|
"I understand, please disable": "Lo comprendo, por favor deshabilitar",
|
||||||
|
Confirm: "Confirmar",
|
||||||
|
Yes: "Sí",
|
||||||
|
No: "No",
|
||||||
|
Username: "Usuario",
|
||||||
|
Password: "Contraseña",
|
||||||
|
"Remember me": "Recordarme",
|
||||||
|
Login: "Acceso",
|
||||||
|
"No Monitors, please": "Sin monitores, por favor",
|
||||||
|
"add one": "añade uno",
|
||||||
|
"Notification Type": "Tipo de notificación",
|
||||||
|
Email: "Email",
|
||||||
|
Test: "Test",
|
||||||
|
"Certificate Info": "Información del certificado ",
|
||||||
|
"Resolver Server": "Servidor de resolución",
|
||||||
|
"Resource Record Type": "Tipo de Registro",
|
||||||
|
"Last Result": "Último resultado",
|
||||||
|
"Create your admin account": "Crea tu cuenta de administrador",
|
||||||
|
"Repeat Password": "Repetir contraseña",
|
||||||
|
respTime: "Tiempo de resp. (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
Create: "Create",
|
||||||
|
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
||||||
|
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
||||||
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
|
"Clear Data": "Clear Data",
|
||||||
|
Events: "Events",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get",
|
||||||
|
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
||||||
|
"Default enabled": "Default enabled",
|
||||||
|
"Also apply to existing monitors": "Also apply to existing monitors",
|
||||||
|
"Import/Export Backup": "Import/Export Backup",
|
||||||
|
Export: "Export",
|
||||||
|
Import: "Import",
|
||||||
|
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
||||||
|
backupDescription2: "PS: History and event data is not included.",
|
||||||
|
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
||||||
|
alertNoFile: "Please select a file to import.",
|
||||||
|
alertWrongFileType: "Please select a JSON file."
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "eesti",
|
||||||
|
checkEverySecond: "Kontrolli {0} sekundilise vahega.",
|
||||||
|
"Avg.": "≈ ",
|
||||||
|
retriesDescription: "Mitu korda tuleb kontrollida, mille järel märkida 'maas' ja saata välja teavitus.",
|
||||||
|
ignoreTLSError: "Eira TLS/SSL viga HTTPS veebisaitidel.",
|
||||||
|
upsideDownModeDescription: "Käitle teenuse saadavust rikkena, teenuse kättesaamatust töötavaks.",
|
||||||
|
maxRedirectDescription: "Suurim arv ümbersuunamisi, millele järgida. 0 ei luba ühtegi ",
|
||||||
|
acceptedStatusCodesDescription: "Vali välja HTTP koodid, mida arvestada kõlblikuks.",
|
||||||
|
passwordNotMatchMsg: "Salasõnad ei kattu.",
|
||||||
|
notificationDescription: "Teavitusmeetodi kasutamiseks seo see seirega.",
|
||||||
|
keywordDescription: "Jälgi võtmesõna HTML või JSON vastustes. (tõstutundlik)",
|
||||||
|
pauseDashboardHome: "Seiskamine",
|
||||||
|
deleteMonitorMsg: "Kas soovid eemaldada seire?",
|
||||||
|
deleteNotificationMsg: "Kas soovid eemaldada selle teavitusmeetodi kõikidelt seiretelt?",
|
||||||
|
resoverserverDescription: "Cloudflare on vaikimisi pöördserver.",
|
||||||
|
rrtypeDescription: "Vali kirje tüüp, mida soovid jälgida.",
|
||||||
|
pauseMonitorMsg: "Kas soovid peatada seire?",
|
||||||
|
Settings: "Seaded",
|
||||||
|
Dashboard: "Töölaud",
|
||||||
|
"New Update": "Uuem tarkvara versioon on saadaval.",
|
||||||
|
Language: "Keel",
|
||||||
|
Appearance: "Välimus",
|
||||||
|
Theme: "Teema",
|
||||||
|
General: "Üldine",
|
||||||
|
Version: "Versioon",
|
||||||
|
"Check Update On GitHub": "Otsi uuendusi GitHub'ist",
|
||||||
|
List: "Nimekiri",
|
||||||
|
Add: "Lisa",
|
||||||
|
"Add New Monitor": "Seire lisamine",
|
||||||
|
"Quick Stats": "Ülevaade",
|
||||||
|
Up: "Töökorras",
|
||||||
|
Down: "Rikkis",
|
||||||
|
Pending: "Määramisel",
|
||||||
|
Unknown: "Teadmata",
|
||||||
|
Pause: "Seiskamine",
|
||||||
|
Name: "Nimi",
|
||||||
|
Status: "Olek",
|
||||||
|
DateTime: "Kuupäev",
|
||||||
|
Message: "Tulemus",
|
||||||
|
"No important events": "Märkimisväärsed juhtumid puuduvad.",
|
||||||
|
Resume: "Taasta",
|
||||||
|
Edit: "Muutmine",
|
||||||
|
Delete: "Eemalda",
|
||||||
|
Current: "Hetkeseisund",
|
||||||
|
Uptime: "Eluiga",
|
||||||
|
"Cert Exp.": "Sert. aegumine",
|
||||||
|
days: "päeva",
|
||||||
|
day: "päev",
|
||||||
|
"-day": "-päev",
|
||||||
|
hour: "tund",
|
||||||
|
"-hour": "-tund",
|
||||||
|
Response: "Vastus",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Seire tüüp",
|
||||||
|
Keyword: "Võtmesõna",
|
||||||
|
"Friendly Name": "Sõbralik nimi",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Hostname",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Tukse sagedus",
|
||||||
|
Retries: "Korduskatsed",
|
||||||
|
Advanced: "Rohkem",
|
||||||
|
"Upside Down Mode": "Tagurpidi seire",
|
||||||
|
"Max. Redirects": "Max. ümbersuunamine",
|
||||||
|
"Accepted Status Codes": "Kõlblikud HTTP koodid",
|
||||||
|
Save: "Salvesta",
|
||||||
|
Notifications: "Teavitused",
|
||||||
|
"Not available, please setup.": "Ühtegi teavitusteenust pole saadaval.",
|
||||||
|
"Setup Notification": "Lisa teavitusteenus",
|
||||||
|
Light: "hele",
|
||||||
|
Dark: "tume",
|
||||||
|
Auto: "automaatne",
|
||||||
|
"Theme - Heartbeat Bar": "Teemasäte — tuksete riba",
|
||||||
|
Normal: "tavaline",
|
||||||
|
Bottom: "all",
|
||||||
|
None: "puudub",
|
||||||
|
Timezone: "Ajatsoon",
|
||||||
|
"Search Engine Visibility": "Otsimootorite ligipääs",
|
||||||
|
"Allow indexing": "Luba indekseerimine",
|
||||||
|
"Discourage search engines from indexing site": "Keela selle saidi indekseerimine otsimootorite poolt",
|
||||||
|
"Change Password": "Muuda parooli",
|
||||||
|
"Current Password": "praegune parool",
|
||||||
|
"New Password": "uus parool",
|
||||||
|
"Repeat New Password": "korda salasõna",
|
||||||
|
"Update Password": "Uuenda salasõna",
|
||||||
|
"Disable Auth": "Lülita autentimine välja",
|
||||||
|
"Enable Auth": "Lülita autentimine sisse",
|
||||||
|
Logout: "Logi välja",
|
||||||
|
Leave: "Lahku",
|
||||||
|
"I understand, please disable": "Olen tutvunud riskidega, lülita välja",
|
||||||
|
Confirm: "Kinnita",
|
||||||
|
Yes: "Jah",
|
||||||
|
No: "Ei",
|
||||||
|
Username: "kasutajanimi",
|
||||||
|
Password: "parool",
|
||||||
|
"Remember me": "Mäleta mind",
|
||||||
|
Login: "Logi sisse",
|
||||||
|
"No Monitors, please": "Seired puuduvad.",
|
||||||
|
"add one": "Lisa esimene",
|
||||||
|
"Notification Type": "Teavituse tüüp",
|
||||||
|
Email: "e-posti aadress",
|
||||||
|
Test: "Saada prooviteavitus",
|
||||||
|
"Certificate Info": "Sertifikaadi teave",
|
||||||
|
"Resolver Server": "Server, mis vastab DNS päringutele.",
|
||||||
|
"Resource Record Type": "DNS kirje tüüp",
|
||||||
|
"Last Result": "Viimane",
|
||||||
|
"Create your admin account": "Admininstraatori konto loomine",
|
||||||
|
"Repeat Password": "korda salasõna",
|
||||||
|
respTime: "Reageerimisaeg (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
||||||
|
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
||||||
|
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
||||||
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
|
"Import/Export Backup": "Import/Export Backup",
|
||||||
|
Export: "Export",
|
||||||
|
Import: "Import",
|
||||||
|
"Default enabled": "Default enabled",
|
||||||
|
"Also apply to existing monitors": "Also apply to existing monitors",
|
||||||
|
Create: "Create",
|
||||||
|
"Clear Data": "Clear Data",
|
||||||
|
Events: "Events",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get",
|
||||||
|
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
||||||
|
backupDescription2: "PS: History and event data is not included.",
|
||||||
|
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
||||||
|
alertNoFile: "Please select a file to import.",
|
||||||
|
alertWrongFileType: "Please select a JSON file."
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Italiano (Italian)",
|
||||||
|
checkEverySecond: "controlla ogni {0} secondi",
|
||||||
|
"Avg.": "Media",
|
||||||
|
retriesDescription: "Tentativi da fare prima che il servizio venga marcato come \"giù\" e che una notifica venga inviata.",
|
||||||
|
ignoreTLSError: "Ignora gli errori TLS/SSL per i siti in HTTPS.",
|
||||||
|
upsideDownModeDescription: "Capovolgi lo stato. Se il servizio è raggiungibile viene marcato come \"GIÙ\".",
|
||||||
|
maxRedirectDescription: "Numero massimo di redirezionamenti consentito. Per disabilitare impostare \"0\".",
|
||||||
|
acceptedStatusCodesDescription: "Inserire i codici di stato considerati come risposte corrette.",
|
||||||
|
passwordNotMatchMsg: "La password non coincide.",
|
||||||
|
notificationDescription: "Assegnare la notifica a uno o più elementi monitorati per metterla in funzione.",
|
||||||
|
keywordDescription: "Cerca la parola chiave nella risposta in html o JSON e fai distinzione tra maiuscole e minuscole",
|
||||||
|
pauseDashboardHome: "In Pausa",
|
||||||
|
deleteMonitorMsg: "Si è certi di voler eliminare questo monitoraggio?",
|
||||||
|
deleteNotificationMsg: "Si è certi di voler eliminare questa notifica per tutti gli oggetti monitorati?",
|
||||||
|
resoverserverDescription: "Cloudflare è il server predefinito, è possibile cambiare il server DNS.",
|
||||||
|
rrtypeDescription: "Scegliere il tipo di RR che si vuole monitorare",
|
||||||
|
pauseMonitorMsg: "Si è certi di voler mettere in pausa?",
|
||||||
|
clearEventsMsg: "Si è certi di voler eliminare tutti gli eventi per questo servizio?",
|
||||||
|
clearHeartbeatsMsg: "Si è certi di voler eliminare tutti gli intervalli di controllo per questo servizio?",
|
||||||
|
confirmClearStatisticsMsg: "Si è certi di voler eliminare TUTTE le statistiche?",
|
||||||
|
Settings: "Impostazioni",
|
||||||
|
Dashboard: "Cruscotto",
|
||||||
|
"New Update": "Nuovo Aggiornamento Disponibile",
|
||||||
|
Language: "Lingua",
|
||||||
|
Appearance: "Aspetto",
|
||||||
|
Theme: "Tema",
|
||||||
|
General: "Generali",
|
||||||
|
Version: "Versione",
|
||||||
|
"Check Update On GitHub": "Controlla aggiornamenti su GitHub",
|
||||||
|
List: "Lista",
|
||||||
|
Add: "Aggiungi",
|
||||||
|
"Add New Monitor": "Aggiungi un nuovo monitoraggio",
|
||||||
|
"Quick Stats": "Statistiche rapide",
|
||||||
|
Up: "Su",
|
||||||
|
Down: "Giù",
|
||||||
|
Pending: "Pendente",
|
||||||
|
Unknown: "Sconosciuti",
|
||||||
|
Pause: "Metti in Pausa",
|
||||||
|
Name: "Nome",
|
||||||
|
Status: "Stato",
|
||||||
|
DateTime: "Data e Ora",
|
||||||
|
Message: "Messaggio",
|
||||||
|
"No important events": "Nessun evento importante",
|
||||||
|
Resume: "Riprendi",
|
||||||
|
Edit: "Modifica",
|
||||||
|
Delete: "Elimina",
|
||||||
|
Current: "Corrente",
|
||||||
|
Uptime: "Tempo di attività",
|
||||||
|
"Cert Exp.": "Scadenza certificato",
|
||||||
|
days: "giorni",
|
||||||
|
day: "giorno",
|
||||||
|
"-day": "-giorni",
|
||||||
|
hour: "ora",
|
||||||
|
"-hour": "-ore",
|
||||||
|
Response: "Risposta",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Tipo di Monitoraggio",
|
||||||
|
Keyword: "Parola chiave",
|
||||||
|
"Friendly Name": "Nome Amichevole",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Nome Host",
|
||||||
|
Port: "Porta",
|
||||||
|
"Heartbeat Interval": "Intervallo di controllo",
|
||||||
|
Retries: "Tentativi",
|
||||||
|
Advanced: "Avanzate",
|
||||||
|
"Upside Down Mode": "Modalità capovolta",
|
||||||
|
"Max. Redirects": "Redirezionamenti massimi",
|
||||||
|
"Accepted Status Codes": "Codici di stato accettati",
|
||||||
|
Save: "Salva",
|
||||||
|
Notifications: "Notifiche",
|
||||||
|
"Not available, please setup.": "Non disponibili, da impostare.",
|
||||||
|
"Setup Notification": "Imposta le notifiche",
|
||||||
|
Light: "Chiaro",
|
||||||
|
Dark: "Scuro",
|
||||||
|
Auto: "Automatico",
|
||||||
|
"Theme - Heartbeat Bar": "Tema - Barra di Stato",
|
||||||
|
Normal: "Normale",
|
||||||
|
Bottom: "Sotto",
|
||||||
|
None: "Nessuna",
|
||||||
|
Timezone: "Fuso Orario",
|
||||||
|
"Search Engine Visibility": "Visibilità ai motori di ricerca",
|
||||||
|
"Allow indexing": "Permetti l'indicizzazione",
|
||||||
|
"Discourage search engines from indexing site": "Scoraggia l'indicizzazione da parte dei motori di ricerca",
|
||||||
|
"Change Password": "Cambio Password",
|
||||||
|
"Current Password": "Password Corrente",
|
||||||
|
"New Password": "Nuova Password",
|
||||||
|
"Repeat New Password": "Ripetere la nuova Password",
|
||||||
|
"Update Password": "Modifica Password",
|
||||||
|
"Disable Auth": "Disabilita l'autenticazione",
|
||||||
|
"Enable Auth": "Abilita Autenticazione",
|
||||||
|
Logout: "Esci",
|
||||||
|
Leave: "Annulla",
|
||||||
|
"I understand, please disable": "Lo capisco, disabilitare l'autenticazione.",
|
||||||
|
Confirm: "Conferma",
|
||||||
|
Yes: "Sì",
|
||||||
|
No: "No",
|
||||||
|
Username: "Nome Utente",
|
||||||
|
Password: "Password",
|
||||||
|
"Remember me": "Ricordami",
|
||||||
|
Login: "Accesso",
|
||||||
|
"No Monitors, please": "Nessun monitoraggio, cortesemente",
|
||||||
|
"add one": "aggiungerne uno",
|
||||||
|
"Notification Type": "Tipo di notifica",
|
||||||
|
Email: "E-mail",
|
||||||
|
Test: "Prova",
|
||||||
|
"Certificate Info": "Informazioni sul certificato",
|
||||||
|
"Resolver Server": "Server DNS",
|
||||||
|
"Resource Record Type": "Tipo di Resource Record",
|
||||||
|
"Last Result": "Ultimo risultato",
|
||||||
|
"Create your admin account": "Crea l'account amministratore",
|
||||||
|
"Repeat Password": "Ripeti Password",
|
||||||
|
respTime: "Tempo di Risposta (ms)",
|
||||||
|
notAvailableShort: "N/D",
|
||||||
|
Create: "Crea",
|
||||||
|
"Clear Data": "Cancella dati",
|
||||||
|
Events: "Eventi",
|
||||||
|
Heartbeats: "Controlli",
|
||||||
|
"Auto Get": "Auto Get",
|
||||||
|
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
||||||
|
"Import/Export Backup": "Import/Export Backup",
|
||||||
|
Export: "Export",
|
||||||
|
Import: "Import",
|
||||||
|
"Default enabled": "Default enabled",
|
||||||
|
"Also apply to existing monitors": "Also apply to existing monitors",
|
||||||
|
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
||||||
|
backupDescription2: "PS: History and event data is not included.",
|
||||||
|
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
||||||
|
alertNoFile: "Please select a file to import.",
|
||||||
|
alertWrongFileType: "Please select a JSON file."
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Polski",
|
||||||
|
checkEverySecond: "Sprawdzaj co {0} sekund.",
|
||||||
|
"Avg.": "Średnia ",
|
||||||
|
retriesDescription: "Maksymalna liczba powtórzeń, zanim usługa zostanie oznaczona jako wyłączona i zostanie wysłane powiadomienie",
|
||||||
|
ignoreTLSError: "Ignoruj błąd TLS/SSL dla stron HTTPS",
|
||||||
|
upsideDownModeDescription: "Odwróć status do góry nogami. Jeśli usługa jest osiągalna, to jest oznaczona jako niedostępna.",
|
||||||
|
maxRedirectDescription: "Maksymalna liczba przekierowań do wykonania. Ustaw na 0, aby wyłączyć przekierowania.",
|
||||||
|
acceptedStatusCodesDescription: "Wybierz kody stanu, które są uważane za udaną odpowiedź.",
|
||||||
|
passwordNotMatchMsg: "Powtórzone hasło nie pasuje.",
|
||||||
|
notificationDescription: "Proszę przypisać powiadomienie do monitora(ów), aby zadziałało.",
|
||||||
|
keywordDescription: "Wyszukiwanie słów kluczowych w zwykłym html lub odpowiedzi JSON. Wielkość liter ma znaczenie.",
|
||||||
|
pauseDashboardHome: "Pauza",
|
||||||
|
deleteMonitorMsg: "Czy na pewno chcesz usunąć ten monitor?",
|
||||||
|
deleteNotificationMsg: "Czy na pewno chcesz usunąć to powiadomienie dla wszystkich monitorów?",
|
||||||
|
resoverserverDescription: "Cloudflare jest domyślnym serwerem, możesz zmienić serwer resolver w każdej chwili.",
|
||||||
|
rrtypeDescription: "Wybierz RR-Type który chcesz monitorować",
|
||||||
|
pauseMonitorMsg: "Czy na pewno chcesz wstrzymać?",
|
||||||
|
Settings: "Ustawienia",
|
||||||
|
Dashboard: "Panel",
|
||||||
|
"New Update": "Nowa aktualizacja",
|
||||||
|
Language: "Język",
|
||||||
|
Appearance: "Wygląd",
|
||||||
|
Theme: "Motyw",
|
||||||
|
General: "Ogólne",
|
||||||
|
Version: "Wersja",
|
||||||
|
"Check Update On GitHub": "Sprawdź aktualizację na GitHub.",
|
||||||
|
List: "Lista",
|
||||||
|
Add: "Dodaj",
|
||||||
|
"Add New Monitor": "Dodaj nowy monitor",
|
||||||
|
"Quick Stats": "Szybkie statystyki",
|
||||||
|
Up: "Online",
|
||||||
|
Down: "Offline",
|
||||||
|
Pending: "Oczekujący",
|
||||||
|
Unknown: "Nieznane",
|
||||||
|
Pause: "Pauza",
|
||||||
|
Name: "Nazwa",
|
||||||
|
Status: "Status",
|
||||||
|
DateTime: "Data i godzina",
|
||||||
|
Message: "Wiadomość",
|
||||||
|
"No important events": "Brak ważnych wydarzeń",
|
||||||
|
Resume: "Wznów",
|
||||||
|
Edit: "Edytuj",
|
||||||
|
Delete: "Usuń",
|
||||||
|
Current: "aktualny",
|
||||||
|
Uptime: "Czas pracy",
|
||||||
|
"Cert Exp.": "Wygaśnięcie certyfikatu",
|
||||||
|
days: "dni",
|
||||||
|
day: "dzień",
|
||||||
|
"-day": " dni",
|
||||||
|
hour: "godzina",
|
||||||
|
"-hour": " godziny",
|
||||||
|
Response: "Odpowiedź",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Typ monitora",
|
||||||
|
Keyword: "Słowo kluczowe",
|
||||||
|
"Friendly Name": "Przyjazna nazwa",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Nazwa hosta",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Interwał bicia serca",
|
||||||
|
Retries: "Prób",
|
||||||
|
Advanced: "Zaawansowane",
|
||||||
|
"Upside Down Mode": "Tryb do góry nogami",
|
||||||
|
"Max. Redirects": "Maks. przekierowania",
|
||||||
|
"Accepted Status Codes": "Akceptowane kody statusu",
|
||||||
|
Save: "Zapisz",
|
||||||
|
Notifications: "Powiadomienia",
|
||||||
|
"Not available, please setup.": "Niedostępne, proszę skonfigurować.",
|
||||||
|
"Setup Notification": "Konfiguracja powiadomień",
|
||||||
|
Light: "Jasny",
|
||||||
|
Dark: "Ciemny",
|
||||||
|
Auto: "Automatyczny",
|
||||||
|
"Theme - Heartbeat Bar": "Motyw - pasek bicia serca",
|
||||||
|
Normal: "Normalne",
|
||||||
|
Bottom: "Na dole",
|
||||||
|
None: "Brak",
|
||||||
|
Timezone: "Strefa czasowa",
|
||||||
|
"Search Engine Visibility": "Widoczność w wyszukiwarce",
|
||||||
|
"Allow indexing": "Pozwól na indeksowanie",
|
||||||
|
"Discourage search engines from indexing site": "Zniechęcaj wyszukiwarki do indeksowania strony",
|
||||||
|
"Change Password": "Zmień hasło",
|
||||||
|
"Current Password": "Aktualne hasło",
|
||||||
|
"New Password": "Nowe hasło",
|
||||||
|
"Repeat New Password": "Powtórz nowe hasło",
|
||||||
|
"Update Password": "Zaktualizuj hasło",
|
||||||
|
"Disable Auth": "Wyłącz autoryzację",
|
||||||
|
"Enable Auth": "Włącz autoryzację ",
|
||||||
|
Logout: "Wyloguj się",
|
||||||
|
Leave: "Zostaw",
|
||||||
|
"I understand, please disable": "Rozumiem, proszę wyłączyć",
|
||||||
|
Confirm: "Potwierdź",
|
||||||
|
Yes: "Tak",
|
||||||
|
No: "Nie",
|
||||||
|
Username: "Nazwa użytkownika",
|
||||||
|
Password: "Hasło",
|
||||||
|
"Remember me": "Zapamiętaj mnie",
|
||||||
|
Login: "Zaloguj się",
|
||||||
|
"No Monitors, please": "Brak monitorów, proszę",
|
||||||
|
"add one": "dodaj jeden",
|
||||||
|
"Notification Type": "Typ powiadomienia",
|
||||||
|
Email: "Email",
|
||||||
|
Test: "Test",
|
||||||
|
"Certificate Info": "Informacje o certyfikacie",
|
||||||
|
"Resolver Server": "Server resolver",
|
||||||
|
"Resource Record Type": "Typ rekordu zasobów",
|
||||||
|
"Last Result": "Ostatni wynik",
|
||||||
|
"Create your admin account": "Utwórz swoje konto administratora",
|
||||||
|
"Repeat Password": "Powtórz hasło",
|
||||||
|
respTime: "Czas odp. (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
Create: "Stwórz",
|
||||||
|
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
||||||
|
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
||||||
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
|
"Clear Data": "Clear Data",
|
||||||
|
Events: "Events",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get",
|
||||||
|
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
||||||
|
"Default enabled": "Default enabled",
|
||||||
|
"Also apply to existing monitors": "Also apply to existing monitors",
|
||||||
|
"Import/Export Backup": "Import/Export Backup",
|
||||||
|
Export: "Export",
|
||||||
|
Import: "Import",
|
||||||
|
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
||||||
|
backupDescription2: "PS: History and event data is not included.",
|
||||||
|
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
||||||
|
alertNoFile: "Please select a file to import.",
|
||||||
|
alertWrongFileType: "Please select a JSON file."
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
export default {
|
||||||
|
languageName: "Srpski",
|
||||||
|
checkEverySecond: "Proveri svakih {0} sekundi.",
|
||||||
|
"Avg.": "Prosečni ",
|
||||||
|
retriesDescription: "Maksimum pokušaja pre nego što se servis obeleži kao neaktivan i pošalje se obaveštenje.",
|
||||||
|
ignoreTLSError: "Ignoriši TLS/SSL greške za HTTPS veb stranice.",
|
||||||
|
upsideDownModeDescription: "Obrnite status. Ako je servis dostupan, onda je obeležen kao neaktivan.",
|
||||||
|
maxRedirectDescription: "Maksimani broj preusmerenja da se prate. Postavite na 0 da bi se isključila preusmerenja.",
|
||||||
|
acceptedStatusCodesDescription: "Odaberite statusne kodove koji se smatraju uspešnim odgovorom.",
|
||||||
|
passwordNotMatchMsg: "Ponovljena lozinka se ne poklapa.",
|
||||||
|
notificationDescription: "Molim Vas postavite obaveštenje za masmatrače da bise aktivirali.",
|
||||||
|
keywordDescription: "Pretraži ključnu reč u čistom html ili JSON odgovoru sa osetljivim velikim i malim slovima",
|
||||||
|
pauseDashboardHome: "Pauziraj",
|
||||||
|
deleteMonitorMsg: "Da li ste sigurni da želite da obrišete ovog posmatrača?",
|
||||||
|
deleteNotificationMsg: "Da li ste sigurni d aželite da uklonite ovo obaveštenje za sve posmatrače?",
|
||||||
|
resoverserverDescription: "Cloudflare je podrazumevani server. Možete promeniti server za raszrešavanje u bilo kom trenutku.",
|
||||||
|
rrtypeDescription: "Odaberite RR-Type koji želite da posmatrate",
|
||||||
|
pauseMonitorMsg: "Da li ste sigurni da želite da pauzirate?",
|
||||||
|
Settings: "Podešavanja",
|
||||||
|
Dashboard: "Komandna tabla",
|
||||||
|
"New Update": "Nova verzija",
|
||||||
|
Language: "Jezik",
|
||||||
|
Appearance: "Izgled",
|
||||||
|
Theme: "Tema",
|
||||||
|
General: "Opšte",
|
||||||
|
Version: "Verzija",
|
||||||
|
"Check Update On GitHub": "Proverite novu verziju na GitHub-u",
|
||||||
|
List: "Lista",
|
||||||
|
Add: "Dodaj",
|
||||||
|
"Add New Monitor": "Dodaj novog posmatrača",
|
||||||
|
"Quick Stats": "Brze statistike",
|
||||||
|
Up: "Aktivno",
|
||||||
|
Down: "Neaktivno",
|
||||||
|
Pending: "Nerešeno",
|
||||||
|
Unknown: "Nepoznato",
|
||||||
|
Pause: "Pauziraj",
|
||||||
|
Name: "Ime",
|
||||||
|
Status: "Status",
|
||||||
|
DateTime: "Datum i vreme",
|
||||||
|
Message: "Poruka",
|
||||||
|
"No important events": "Nema bitnih događaja",
|
||||||
|
Resume: "Nastavi",
|
||||||
|
Edit: "Izmeni",
|
||||||
|
Delete: "Ukloni",
|
||||||
|
Current: "Trenutno",
|
||||||
|
Uptime: "Vreme rada",
|
||||||
|
"Cert Exp.": "Istek sert.",
|
||||||
|
days: "dana",
|
||||||
|
day: "dan",
|
||||||
|
"-day": "-dana",
|
||||||
|
hour: "sat",
|
||||||
|
"-hour": "-sata",
|
||||||
|
Response: "Odgovor",
|
||||||
|
Ping: "Ping",
|
||||||
|
"Monitor Type": "Tip posmatrača",
|
||||||
|
Keyword: "Ključna reč",
|
||||||
|
"Friendly Name": "Prijateljsko ime",
|
||||||
|
URL: "URL",
|
||||||
|
Hostname: "Hostname",
|
||||||
|
Port: "Port",
|
||||||
|
"Heartbeat Interval": "Interval otkucaja srca",
|
||||||
|
Retries: "Pokušaji",
|
||||||
|
Advanced: "Napredno",
|
||||||
|
"Upside Down Mode": "Naopak mod",
|
||||||
|
"Max. Redirects": "Maks. preusmerenja",
|
||||||
|
"Accepted Status Codes": "Prihvaćeni statusni kodovi",
|
||||||
|
Save: "Sačuvaj",
|
||||||
|
Notifications: "Obaveštenja",
|
||||||
|
"Not available, please setup.": "Nije dostupno, molim Vas podesite.",
|
||||||
|
"Setup Notification": "Postavi obaveštenje",
|
||||||
|
Light: "Svetlo",
|
||||||
|
Dark: "Tamno",
|
||||||
|
Auto: "Automatsko",
|
||||||
|
"Theme - Heartbeat Bar": "Tema - Traka otkucaja srca",
|
||||||
|
Normal: "Normalno",
|
||||||
|
Bottom: "Dole",
|
||||||
|
None: "Isključeno",
|
||||||
|
Timezone: "Vremenska zona",
|
||||||
|
"Search Engine Visibility": "Vidljivost pretraživačima",
|
||||||
|
"Allow indexing": "Dozvoli indeksiranje",
|
||||||
|
"Discourage search engines from indexing site": "Odvraćajte pretraživače od indeksiranja sajta",
|
||||||
|
"Change Password": "Promeni lozinku",
|
||||||
|
"Current Password": "Trenutna lozinka",
|
||||||
|
"New Password": "Nova lozinka",
|
||||||
|
"Repeat New Password": "Ponovi novu lozinku",
|
||||||
|
"Update Password": "Izmeni lozinku",
|
||||||
|
"Disable Auth": "Isključi autentifikaciju",
|
||||||
|
"Enable Auth": "Uključi autentifikaciju",
|
||||||
|
Logout: "Odloguj se",
|
||||||
|
Leave: "Izađi",
|
||||||
|
"I understand, please disable": "Razumem, molim te isključi",
|
||||||
|
Confirm: "Potvrdi",
|
||||||
|
Yes: "Da",
|
||||||
|
No: "Ne",
|
||||||
|
Username: "Korisničko ime",
|
||||||
|
Password: "Lozinka",
|
||||||
|
"Remember me": "Zapamti me",
|
||||||
|
Login: "Uloguj se",
|
||||||
|
"No Monitors, please": "Bez posmatrača molim",
|
||||||
|
"add one": "dodaj jednog",
|
||||||
|
"Notification Type": "Tip obaveštenja",
|
||||||
|
Email: "E-pošta",
|
||||||
|
Test: "Test",
|
||||||
|
"Certificate Info": "Informacije sertifikata",
|
||||||
|
"Resolver Server": "Razrešivački server",
|
||||||
|
"Resource Record Type": "Tip zapisa resursa",
|
||||||
|
"Last Result": "Poslednji rezultat",
|
||||||
|
"Create your admin account": "Naprivi administratorski nalog",
|
||||||
|
"Repeat Password": "Ponovite lozinku",
|
||||||
|
respTime: "Vreme odg. (ms)",
|
||||||
|
notAvailableShort: "N/A",
|
||||||
|
Create: "Create",
|
||||||
|
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
||||||
|
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
||||||
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
|
"Clear Data": "Clear Data",
|
||||||
|
Events: "Events",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get",
|
||||||
|
enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
|
||||||
|
"Default enabled": "Default enabled",
|
||||||
|
"Also apply to existing monitors": "Also apply to existing monitors",
|
||||||
|
"Import/Export Backup": "Import/Export Backup",
|
||||||
|
Export: "Export",
|
||||||
|
Import: "Import",
|
||||||
|
backupDescription: "You can backup all monitors and all notifications into a JSON file.",
|
||||||
|
backupDescription2: "PS: History and event data is not included.",
|
||||||
|
backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
|
||||||
|
alertNoFile: "Please select a file to import.",
|
||||||
|
alertWrongFileType: "Please select a JSON file."
|
||||||
|
}
|
Loading…
Reference in new issue