mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-09-18 09:26:56 +08:00
Compare commits
74 Commits
1.19.0-bet
...
1.19.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
b1170211b7 | ||
|
eadf2c810a | ||
|
8aa97635ec | ||
|
ee1a56caae | ||
|
e886df4788 | ||
|
5196abfd36 | ||
|
3e68cf2a1c | ||
|
0ab82e6de3 | ||
|
8cdbe37f6f | ||
|
28d13e198c | ||
|
14a062804e | ||
|
cf3e03ab40 | ||
|
191f3ad53b | ||
|
370d522920 | ||
|
e0a1ad8a1c | ||
|
9720006934 | ||
|
cd270bd8b5 | ||
|
bc3229828e | ||
|
a5f23b9839 | ||
|
2052fa175f | ||
|
15b63c82c3 | ||
|
b053bc61ce | ||
|
258ff56962 | ||
|
cb4e512dc6 | ||
|
4042c26390 | ||
|
5da2315534 | ||
|
204015f1f5 | ||
|
cc6d17d2e0 | ||
|
68862c0b3f | ||
|
fd15e7c2dc | ||
|
5c4cf68937 | ||
|
214ddc264d | ||
|
2ea71839d1 | ||
|
54efde8185 | ||
|
705124d4ac | ||
|
1cb6940590 | ||
|
0f8ad288f3 | ||
|
434174d350 | ||
|
3d1237ed53 | ||
|
b459408b10 | ||
|
f04fe4d230 | ||
|
e579610426 | ||
|
b115d3f8b9 | ||
|
134b3b8ac1 | ||
|
e7e7751e7b | ||
|
5cd58e6fa3 | ||
|
08763b700a | ||
|
781f855921 | ||
|
9e81fe120f | ||
|
c0e67b6de9 | ||
|
a17084f75d | ||
|
e4fe7b802a | ||
|
5761bc9b90 | ||
|
92ea019fd4 | ||
|
a774b37369 | ||
|
1e8a16504b | ||
|
b879428a03 | ||
|
3c5de1c889 | ||
|
f9be918246 | ||
|
314ae38f91 | ||
|
c03d911657 | ||
|
e12642cf21 | ||
|
618d904001 | ||
|
6f86236b63 | ||
|
68875c3091 | ||
|
f35d7c0a1a | ||
|
3a90d246a4 | ||
|
6bb79597e8 | ||
|
34ab6142db | ||
|
2232236a7a | ||
|
dcecd10c88 | ||
|
af07c7f050 | ||
|
95dba6dcaf | ||
|
90c2bf7c94 |
25
db/patch-grpc-monitor.sql
Normal file
25
db/patch-grpc-monitor.sql
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD grpc_url VARCHAR(255) default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD grpc_protobuf TEXT default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD grpc_body TEXT default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD grpc_metadata TEXT default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD grpc_method VARCHAR(255) default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD grpc_service_name VARCHAR(255) default null;
|
||||||
|
|
||||||
|
ALTER TABLE monitor
|
||||||
|
ADD grpc_enable_tls BOOLEAN default 0 not null;
|
||||||
|
|
||||||
|
COMMIT;
|
@@ -4,5 +4,5 @@ WORKDIR /app
|
|||||||
|
|
||||||
# Install apprise, iputils for non-root ping, setpriv
|
# Install apprise, iputils for non-root ping, setpriv
|
||||||
RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \
|
RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \
|
||||||
pip3 --no-cache-dir install apprise==1.0.0 && \
|
pip3 --no-cache-dir install apprise==1.2.0 && \
|
||||||
rm -rf /root/.cache
|
rm -rf /root/.cache
|
||||||
|
@@ -11,7 +11,7 @@ WORKDIR /app
|
|||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
|
apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
|
||||||
sqlite3 iputils-ping util-linux dumb-init && \
|
sqlite3 iputils-ping util-linux dumb-init && \
|
||||||
pip3 --no-cache-dir install apprise==1.0.0 && \
|
pip3 --no-cache-dir install apprise==1.2.0 && \
|
||||||
rm -rf /var/lib/apt/lists/* && \
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
apt --yes autoremove
|
apt --yes autoremove
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ const util = require("../src/util");
|
|||||||
util.polyfill();
|
util.polyfill();
|
||||||
|
|
||||||
const oldVersion = pkg.version;
|
const oldVersion = pkg.version;
|
||||||
const newVersion = oldVersion + "-nightly";
|
const newVersion = oldVersion + "-nightly-" + util.genSecret(8);
|
||||||
|
|
||||||
console.log("Old Version: " + oldVersion);
|
console.log("Old Version: " + oldVersion);
|
||||||
console.log("New Version: " + newVersion);
|
console.log("New Version: " + newVersion);
|
||||||
|
5008
package-lock.json
generated
5008
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uptime-kuma",
|
"name": "uptime-kuma",
|
||||||
"version": "1.19.0-beta.0",
|
"version": "1.19.0-beta.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -63,10 +63,11 @@
|
|||||||
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\""
|
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\""
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@grpc/grpc-js": "~1.7.3",
|
||||||
"@louislam/sqlite3": "15.1.2",
|
"@louislam/sqlite3": "15.1.2",
|
||||||
"args-parser": "~1.3.0",
|
"args-parser": "~1.3.0",
|
||||||
"axios": "~0.27.0",
|
"axios": "~0.27.0",
|
||||||
"axios-ntlm": "~1.3.0",
|
"axios-ntlm": "1.3.0",
|
||||||
"badge-maker": "~3.3.1",
|
"badge-maker": "~3.3.1",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
"bree": "~7.1.5",
|
"bree": "~7.1.5",
|
||||||
@@ -93,6 +94,7 @@
|
|||||||
"limiter": "~2.1.0",
|
"limiter": "~2.1.0",
|
||||||
"mqtt": "~4.3.7",
|
"mqtt": "~4.3.7",
|
||||||
"mssql": "~8.1.4",
|
"mssql": "~8.1.4",
|
||||||
|
"mysql2": "~2.3.3",
|
||||||
"node-cloudflared-tunnel": "~1.0.9",
|
"node-cloudflared-tunnel": "~1.0.9",
|
||||||
"node-radius-client": "~1.0.0",
|
"node-radius-client": "~1.0.0",
|
||||||
"nodemailer": "~6.6.5",
|
"nodemailer": "~6.6.5",
|
||||||
@@ -102,9 +104,10 @@
|
|||||||
"pg-connection-string": "~2.5.0",
|
"pg-connection-string": "~2.5.0",
|
||||||
"prom-client": "~13.2.0",
|
"prom-client": "~13.2.0",
|
||||||
"prometheus-api-metrics": "~3.2.1",
|
"prometheus-api-metrics": "~3.2.1",
|
||||||
|
"protobufjs": "~7.1.1",
|
||||||
"redbean-node": "0.1.4",
|
"redbean-node": "0.1.4",
|
||||||
"socket.io": "~4.4.1",
|
"socket.io": "~4.5.3",
|
||||||
"socket.io-client": "~4.4.1",
|
"socket.io-client": "~4.5.3",
|
||||||
"socks-proxy-agent": "6.1.1",
|
"socks-proxy-agent": "6.1.1",
|
||||||
"tar": "~6.1.11",
|
"tar": "~6.1.11",
|
||||||
"tcp-ping": "~0.1.1",
|
"tcp-ping": "~0.1.1",
|
||||||
@@ -130,7 +133,7 @@
|
|||||||
"chart.js": "~3.6.2",
|
"chart.js": "~3.6.2",
|
||||||
"chartjs-adapter-dayjs": "~1.0.0",
|
"chartjs-adapter-dayjs": "~1.0.0",
|
||||||
"concurrently": "^7.1.0",
|
"concurrently": "^7.1.0",
|
||||||
"core-js": "~3.18.3",
|
"core-js": "~3.26.1",
|
||||||
"cross-env": "~7.0.3",
|
"cross-env": "~7.0.3",
|
||||||
"cypress": "^10.1.0",
|
"cypress": "^10.1.0",
|
||||||
"delay": "^5.0.0",
|
"delay": "^5.0.0",
|
||||||
|
@@ -25,7 +25,7 @@ exports.startInterval = () => {
|
|||||||
let checkBeta = await setting("checkBeta");
|
let checkBeta = await setting("checkBeta");
|
||||||
|
|
||||||
if (checkBeta && res.data.beta) {
|
if (checkBeta && res.data.beta) {
|
||||||
if (compareVersions.compare(res.data.beta, res.data.beta, ">")) {
|
if (compareVersions.compare(res.data.beta, res.data.slow, ">")) {
|
||||||
exports.latestVersion = res.data.beta;
|
exports.latestVersion = res.data.beta;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -62,6 +62,7 @@ class Database {
|
|||||||
"patch-add-clickable-status-page-link.sql": true,
|
"patch-add-clickable-status-page-link.sql": true,
|
||||||
"patch-add-sqlserver-monitor.sql": true,
|
"patch-add-sqlserver-monitor.sql": true,
|
||||||
"patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] },
|
"patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] },
|
||||||
|
"patch-grpc-monitor.sql": true,
|
||||||
"patch-add-radius-monitor.sql": true,
|
"patch-add-radius-monitor.sql": true,
|
||||||
"patch-monitor-add-resend-interval.sql": true,
|
"patch-monitor-add-resend-interval.sql": true,
|
||||||
"patch-maintenance-table2.sql": true,
|
"patch-maintenance-table2.sql": true,
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
const dayjs = require("dayjs");
|
|
||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -3,7 +3,7 @@ const dayjs = require("dayjs");
|
|||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const { Prometheus } = require("../prometheus");
|
const { Prometheus } = require("../prometheus");
|
||||||
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger } = require("../../src/util");
|
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger } = require("../../src/util");
|
||||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mqttAsync, setSetting, httpNtlm, radius } = require("../util-server");
|
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery } = require("../util-server");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||||
const { Notification } = require("../notification");
|
const { Notification } = require("../notification");
|
||||||
@@ -89,27 +89,23 @@ class Monitor extends BeanModel {
|
|||||||
dns_resolve_type: this.dns_resolve_type,
|
dns_resolve_type: this.dns_resolve_type,
|
||||||
dns_resolve_server: this.dns_resolve_server,
|
dns_resolve_server: this.dns_resolve_server,
|
||||||
dns_last_result: this.dns_last_result,
|
dns_last_result: this.dns_last_result,
|
||||||
pushToken: this.pushToken,
|
|
||||||
docker_container: this.docker_container,
|
docker_container: this.docker_container,
|
||||||
docker_host: this.docker_host,
|
docker_host: this.docker_host,
|
||||||
proxyId: this.proxy_id,
|
proxyId: this.proxy_id,
|
||||||
notificationIDList,
|
notificationIDList,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
maintenance: await Monitor.isUnderMaintenance(this.id),
|
maintenance: await Monitor.isUnderMaintenance(this.id),
|
||||||
mqttUsername: this.mqttUsername,
|
|
||||||
mqttPassword: this.mqttPassword,
|
|
||||||
mqttTopic: this.mqttTopic,
|
mqttTopic: this.mqttTopic,
|
||||||
mqttSuccessMessage: this.mqttSuccessMessage,
|
mqttSuccessMessage: this.mqttSuccessMessage,
|
||||||
databaseConnectionString: this.databaseConnectionString,
|
|
||||||
databaseQuery: this.databaseQuery,
|
databaseQuery: this.databaseQuery,
|
||||||
authMethod: this.authMethod,
|
authMethod: this.authMethod,
|
||||||
authWorkstation: this.authWorkstation,
|
grpcUrl: this.grpcUrl,
|
||||||
authDomain: this.authDomain,
|
grpcProtobuf: this.grpcProtobuf,
|
||||||
radiusUsername: this.radiusUsername,
|
grpcMethod: this.grpcMethod,
|
||||||
radiusPassword: this.radiusPassword,
|
grpcServiceName: this.grpcServiceName,
|
||||||
|
grpcEnableTls: this.getGrpcEnableTls(),
|
||||||
radiusCalledStationId: this.radiusCalledStationId,
|
radiusCalledStationId: this.radiusCalledStationId,
|
||||||
radiusCallingStationId: this.radiusCallingStationId,
|
radiusCallingStationId: this.radiusCallingStationId,
|
||||||
radiusSecret: this.radiusSecret,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (includeSensitiveData) {
|
if (includeSensitiveData) {
|
||||||
@@ -117,12 +113,23 @@ class Monitor extends BeanModel {
|
|||||||
...data,
|
...data,
|
||||||
headers: this.headers,
|
headers: this.headers,
|
||||||
body: this.body,
|
body: this.body,
|
||||||
|
grpcBody: this.grpcBody,
|
||||||
|
grpcMetadata: this.grpcMetadata,
|
||||||
basic_auth_user: this.basic_auth_user,
|
basic_auth_user: this.basic_auth_user,
|
||||||
basic_auth_pass: this.basic_auth_pass,
|
basic_auth_pass: this.basic_auth_pass,
|
||||||
pushToken: this.pushToken,
|
pushToken: this.pushToken,
|
||||||
|
databaseConnectionString: this.databaseConnectionString,
|
||||||
|
radiusUsername: this.radiusUsername,
|
||||||
|
radiusPassword: this.radiusPassword,
|
||||||
|
radiusSecret: this.radiusSecret,
|
||||||
|
mqttUsername: this.mqttUsername,
|
||||||
|
mqttPassword: this.mqttPassword,
|
||||||
|
authWorkstation: this.authWorkstation,
|
||||||
|
authDomain: this.authDomain,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.includeSensitiveData = includeSensitiveData;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +174,14 @@ class Monitor extends BeanModel {
|
|||||||
return Boolean(this.upsideDown);
|
return Boolean(this.upsideDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse to boolean
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
getGrpcEnableTls() {
|
||||||
|
return Boolean(this.grpcEnableTls);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get accepted status codes
|
* Get accepted status codes
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
@@ -252,17 +267,22 @@ class Monitor extends BeanModel {
|
|||||||
|
|
||||||
log.debug("monitor", `[${this.name}] Prepare Options for axios`);
|
log.debug("monitor", `[${this.name}] Prepare Options for axios`);
|
||||||
|
|
||||||
|
// Axios Options
|
||||||
const options = {
|
const options = {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
method: (this.method || "get").toLowerCase(),
|
method: (this.method || "get").toLowerCase(),
|
||||||
...(this.body ? { data: JSON.parse(this.body) } : {}),
|
...(this.body ? { data: JSON.parse(this.body) } : {}),
|
||||||
timeout: this.interval * 1000 * 0.8,
|
timeout: this.interval * 1000 * 0.8,
|
||||||
headers: {
|
headers: {
|
||||||
|
// Fix #2253
|
||||||
|
// Read more: https://stackoverflow.com/questions/1759956/curl-error-18-transfer-closed-with-outstanding-read-data-remaining
|
||||||
|
"Accept-Encoding": "gzip, deflate",
|
||||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
|
||||||
"User-Agent": "Uptime-Kuma/" + version,
|
"User-Agent": "Uptime-Kuma/" + version,
|
||||||
...(this.headers ? JSON.parse(this.headers) : {}),
|
...(this.headers ? JSON.parse(this.headers) : {}),
|
||||||
...(basicAuthHeader),
|
...(basicAuthHeader),
|
||||||
},
|
},
|
||||||
|
decompress: true,
|
||||||
maxRedirects: this.maxredirects,
|
maxRedirects: this.maxredirects,
|
||||||
validateStatus: (status) => {
|
validateStatus: (status) => {
|
||||||
return checkStatusCode(status, this.getAcceptedStatuscodes());
|
return checkStatusCode(status, this.getAcceptedStatuscodes());
|
||||||
@@ -527,11 +547,50 @@ class Monitor extends BeanModel {
|
|||||||
bean.msg = "";
|
bean.msg = "";
|
||||||
bean.status = UP;
|
bean.status = UP;
|
||||||
bean.ping = dayjs().valueOf() - startTime;
|
bean.ping = dayjs().valueOf() - startTime;
|
||||||
|
} else if (this.type === "grpc-keyword") {
|
||||||
|
let startTime = dayjs().valueOf();
|
||||||
|
const options = {
|
||||||
|
grpcUrl: this.grpcUrl,
|
||||||
|
grpcProtobufData: this.grpcProtobuf,
|
||||||
|
grpcServiceName: this.grpcServiceName,
|
||||||
|
grpcEnableTls: this.grpcEnableTls,
|
||||||
|
grpcMethod: this.grpcMethod,
|
||||||
|
grpcBody: this.grpcBody,
|
||||||
|
keyword: this.keyword
|
||||||
|
};
|
||||||
|
const response = await grpcQuery(options);
|
||||||
|
bean.ping = dayjs().valueOf() - startTime;
|
||||||
|
log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`);
|
||||||
|
let responseData = response.data;
|
||||||
|
if (responseData.length > 50) {
|
||||||
|
responseData = response.substring(0, 47) + "...";
|
||||||
|
}
|
||||||
|
if (response.code !== 1) {
|
||||||
|
bean.status = DOWN;
|
||||||
|
bean.msg = `Error in send gRPC ${response.code} ${response.errorMessage}`;
|
||||||
|
} else {
|
||||||
|
if (response.data.toString().includes(this.keyword)) {
|
||||||
|
bean.status = UP;
|
||||||
|
bean.msg = `${responseData}, keyword [${this.keyword}] is found`;
|
||||||
|
} else {
|
||||||
|
log.debug("monitor:", `GRPC response [${response.data}] + ", but keyword [${this.keyword}] is not in [" + ${response.data} + "]"`);
|
||||||
|
bean.status = DOWN;
|
||||||
|
bean.msg = `, but keyword [${this.keyword}] is not in [" + ${responseData} + "]`;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (this.type === "postgres") {
|
} else if (this.type === "postgres") {
|
||||||
let startTime = dayjs().valueOf();
|
let startTime = dayjs().valueOf();
|
||||||
|
|
||||||
await postgresQuery(this.databaseConnectionString, this.databaseQuery);
|
await postgresQuery(this.databaseConnectionString, this.databaseQuery);
|
||||||
|
|
||||||
|
bean.msg = "";
|
||||||
|
bean.status = UP;
|
||||||
|
bean.ping = dayjs().valueOf() - startTime;
|
||||||
|
} else if (this.type === "mysql") {
|
||||||
|
let startTime = dayjs().valueOf();
|
||||||
|
|
||||||
|
await mysqlQuery(this.databaseConnectionString, this.databaseQuery);
|
||||||
|
|
||||||
bean.msg = "";
|
bean.msg = "";
|
||||||
bean.status = UP;
|
bean.status = UP;
|
||||||
bean.ping = dayjs().valueOf() - startTime;
|
bean.ping = dayjs().valueOf() - startTime;
|
||||||
|
@@ -38,7 +38,7 @@ class StatusPage extends BeanModel {
|
|||||||
*/
|
*/
|
||||||
static async renderHTML(indexHTML, statusPage) {
|
static async renderHTML(indexHTML, statusPage) {
|
||||||
const $ = cheerio.load(indexHTML);
|
const $ = cheerio.load(indexHTML);
|
||||||
const description155 = statusPage.description?.substring(0, 155);
|
const description155 = statusPage.description?.substring(0, 155) ?? "";
|
||||||
|
|
||||||
$("title").text(statusPage.title);
|
$("title").text(statusPage.title);
|
||||||
$("meta[name=description]").attr("content", description155);
|
$("meta[name=description]").attr("content", description155);
|
||||||
|
@@ -20,6 +20,11 @@ class Ntfy extends NotificationProvider {
|
|||||||
"priority": notification.ntfyPriority || 4,
|
"priority": notification.ntfyPriority || 4,
|
||||||
"title": "Uptime-Kuma",
|
"title": "Uptime-Kuma",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (notification.ntfyIcon) {
|
||||||
|
data.icon = notification.ntfyIcon;
|
||||||
|
}
|
||||||
|
|
||||||
await axios.post(`${notification.ntfyserverurl}`, data, { headers: headers });
|
await axios.post(`${notification.ntfyserverurl}`, data, { headers: headers });
|
||||||
|
|
||||||
return okMsg;
|
return okMsg;
|
||||||
|
@@ -19,26 +19,26 @@ class Pushbullet extends NotificationProvider {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (heartbeatJSON == null) {
|
if (heartbeatJSON == null) {
|
||||||
let testdata = {
|
let data = {
|
||||||
"type": "note",
|
"type": "note",
|
||||||
"title": "Uptime Kuma Alert",
|
"title": "Uptime Kuma Alert",
|
||||||
"body": "Testing Successful.",
|
"body": msg,
|
||||||
};
|
};
|
||||||
await axios.post(pushbulletUrl, testdata, config);
|
await axios.post(pushbulletUrl, data, config);
|
||||||
} else if (heartbeatJSON["status"] === DOWN) {
|
} else if (heartbeatJSON["status"] === DOWN) {
|
||||||
let downdata = {
|
let downData = {
|
||||||
"type": "note",
|
"type": "note",
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
};
|
};
|
||||||
await axios.post(pushbulletUrl, downdata, config);
|
await axios.post(pushbulletUrl, downData, config);
|
||||||
} else if (heartbeatJSON["status"] === UP) {
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
let updata = {
|
let upData = {
|
||||||
"type": "note",
|
"type": "note",
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
};
|
};
|
||||||
await axios.post(pushbulletUrl, updata, config);
|
await axios.post(pushbulletUrl, upData, config);
|
||||||
}
|
}
|
||||||
return okMsg;
|
return okMsg;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
71
server/notification-providers/smseagle.js
Normal file
71
server/notification-providers/smseagle.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class SMSEagle extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "SMSEagle";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let postData;
|
||||||
|
let sendMethod;
|
||||||
|
let recipientType;
|
||||||
|
|
||||||
|
let encoding = (notification.smseagleEncoding) ? "1" : "0";
|
||||||
|
let priority = (notification.smseaglePriority) ? notification.smseaglePriority : "0";
|
||||||
|
|
||||||
|
if (notification.smseagleRecipientType === "smseagle-contact") {
|
||||||
|
recipientType = "contactname";
|
||||||
|
sendMethod = "sms.send_tocontact";
|
||||||
|
}
|
||||||
|
if (notification.smseagleRecipientType === "smseagle-group") {
|
||||||
|
recipientType = "groupname";
|
||||||
|
sendMethod = "sms.send_togroup";
|
||||||
|
}
|
||||||
|
if (notification.smseagleRecipientType === "smseagle-to") {
|
||||||
|
recipientType = "to";
|
||||||
|
sendMethod = "sms.send_sms";
|
||||||
|
}
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
access_token: notification.smseagleToken,
|
||||||
|
[recipientType]: notification.smseagleRecipient,
|
||||||
|
message: msg,
|
||||||
|
responsetype: "extended",
|
||||||
|
unicode: encoding,
|
||||||
|
highpriority: priority
|
||||||
|
};
|
||||||
|
|
||||||
|
postData = {
|
||||||
|
method: sendMethod,
|
||||||
|
params: params
|
||||||
|
};
|
||||||
|
|
||||||
|
let resp = await axios.post(notification.smseagleUrl + "/jsonrpc/sms", postData, config);
|
||||||
|
|
||||||
|
if ((JSON.stringify(resp.data)).indexOf("message_id") === -1) {
|
||||||
|
let error = "";
|
||||||
|
if (resp.data.result && resp.data.result.error_text) {
|
||||||
|
error = `SMSEagle API returned error: ${JSON.stringify(resp.data.result.error_text)}`;
|
||||||
|
} else {
|
||||||
|
error = "SMSEagle API returned an unexpected response";
|
||||||
|
}
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SMSEagle;
|
@@ -16,20 +16,29 @@ class Webhook extends NotificationProvider {
|
|||||||
msg,
|
msg,
|
||||||
};
|
};
|
||||||
let finalData;
|
let finalData;
|
||||||
let config = {};
|
let config = {
|
||||||
|
headers: {}
|
||||||
|
};
|
||||||
|
|
||||||
if (notification.webhookContentType === "form-data") {
|
if (notification.webhookContentType === "form-data") {
|
||||||
finalData = new FormData();
|
finalData = new FormData();
|
||||||
finalData.append("data", JSON.stringify(data));
|
finalData.append("data", JSON.stringify(data));
|
||||||
|
config.headers = finalData.getHeaders();
|
||||||
config = {
|
|
||||||
headers: finalData.getHeaders(),
|
|
||||||
};
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
finalData = data;
|
finalData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (notification.webhookAdditionalHeaders) {
|
||||||
|
try {
|
||||||
|
config.headers = {
|
||||||
|
...config.headers,
|
||||||
|
...JSON.parse(notification.webhookAdditionalHeaders)
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
throw "Additional Headers is not a valid JSON";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await axios.post(notification.webhookURL, finalData, config);
|
await axios.post(notification.webhookURL, finalData, config);
|
||||||
return okMsg;
|
return okMsg;
|
||||||
|
|
||||||
|
@@ -32,6 +32,7 @@ const RocketChat = require("./notification-providers/rocket-chat");
|
|||||||
const SerwerSMS = require("./notification-providers/serwersms");
|
const SerwerSMS = require("./notification-providers/serwersms");
|
||||||
const Signal = require("./notification-providers/signal");
|
const Signal = require("./notification-providers/signal");
|
||||||
const Slack = require("./notification-providers/slack");
|
const Slack = require("./notification-providers/slack");
|
||||||
|
const SMSEagle = require("./notification-providers/smseagle");
|
||||||
const SMTP = require("./notification-providers/smtp");
|
const SMTP = require("./notification-providers/smtp");
|
||||||
const Squadcast = require("./notification-providers/squadcast");
|
const Squadcast = require("./notification-providers/squadcast");
|
||||||
const Stackfield = require("./notification-providers/stackfield");
|
const Stackfield = require("./notification-providers/stackfield");
|
||||||
@@ -89,6 +90,7 @@ class Notification {
|
|||||||
new Signal(),
|
new Signal(),
|
||||||
new SMSManager(),
|
new SMSManager(),
|
||||||
new Slack(),
|
new Slack(),
|
||||||
|
new SMSEagle(),
|
||||||
new SMTP(),
|
new SMTP(),
|
||||||
new Squadcast(),
|
new Squadcast(),
|
||||||
new Stackfield(),
|
new Stackfield(),
|
||||||
|
@@ -7,7 +7,7 @@ const { UptimeKumaServer } = require("./uptime-kuma-server");
|
|||||||
|
|
||||||
class Proxy {
|
class Proxy {
|
||||||
|
|
||||||
static SUPPORTED_PROXY_PROTOCOLS = [ "http", "https", "socks", "socks5", "socks4" ];
|
static SUPPORTED_PROXY_PROTOCOLS = [ "http", "https", "socks", "socks5", "socks5h", "socks4" ];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves and updates given proxy entity
|
* Saves and updates given proxy entity
|
||||||
@@ -126,6 +126,7 @@ class Proxy {
|
|||||||
break;
|
break;
|
||||||
case "socks":
|
case "socks":
|
||||||
case "socks5":
|
case "socks5":
|
||||||
|
case "socks5h":
|
||||||
case "socks4":
|
case "socks4":
|
||||||
agent = new SocksProxyAgent({
|
agent = new SocksProxyAgent({
|
||||||
...httpAgentOptions,
|
...httpAgentOptions,
|
||||||
|
@@ -203,6 +203,7 @@ let needSetup = false;
|
|||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
app.post("/test-webhook", async (request, response) => {
|
app.post("/test-webhook", async (request, response) => {
|
||||||
|
log.debug("test", request.headers);
|
||||||
log.debug("test", request.body);
|
log.debug("test", request.body);
|
||||||
response.send("OK");
|
response.send("OK");
|
||||||
});
|
});
|
||||||
@@ -706,6 +707,12 @@ let needSetup = false;
|
|||||||
bean.authMethod = monitor.authMethod;
|
bean.authMethod = monitor.authMethod;
|
||||||
bean.authWorkstation = monitor.authWorkstation;
|
bean.authWorkstation = monitor.authWorkstation;
|
||||||
bean.authDomain = monitor.authDomain;
|
bean.authDomain = monitor.authDomain;
|
||||||
|
bean.grpcUrl = monitor.grpcUrl;
|
||||||
|
bean.grpcProtobuf = monitor.grpcProtobuf;
|
||||||
|
bean.grpcMethod = monitor.grpcMethod;
|
||||||
|
bean.grpcBody = monitor.grpcBody;
|
||||||
|
bean.grpcMetadata = monitor.grpcMetadata;
|
||||||
|
bean.grpcEnableTls = monitor.grpcEnableTls;
|
||||||
bean.radiusUsername = monitor.radiusUsername;
|
bean.radiusUsername = monitor.radiusUsername;
|
||||||
bean.radiusPassword = monitor.radiusPassword;
|
bean.radiusPassword = monitor.radiusPassword;
|
||||||
bean.radiusCalledStationId = monitor.radiusCalledStationId;
|
bean.radiusCalledStationId = monitor.radiusCalledStationId;
|
||||||
|
@@ -13,8 +13,11 @@ const { badgeConstants } = require("./config");
|
|||||||
const mssql = require("mssql");
|
const mssql = require("mssql");
|
||||||
const { Client } = require("pg");
|
const { Client } = require("pg");
|
||||||
const postgresConParse = require("pg-connection-string").parse;
|
const postgresConParse = require("pg-connection-string").parse;
|
||||||
|
const mysql = require("mysql2");
|
||||||
const { NtlmClient } = require("axios-ntlm");
|
const { NtlmClient } = require("axios-ntlm");
|
||||||
const { Settings } = require("./settings");
|
const { Settings } = require("./settings");
|
||||||
|
const grpc = require("@grpc/grpc-js");
|
||||||
|
const protojs = require("protobufjs");
|
||||||
const radiusClient = require("node-radius-client");
|
const radiusClient = require("node-radius-client");
|
||||||
const {
|
const {
|
||||||
dictionaries: {
|
dictionaries: {
|
||||||
@@ -292,6 +295,28 @@ exports.postgresQuery = function (connectionString, query) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run a query on MySQL/MariaDB
|
||||||
|
* @param {string} connectionString The database connection string
|
||||||
|
* @param {string} query The query to validate the database with
|
||||||
|
* @returns {Promise<(string[]|Object[]|Object)>}
|
||||||
|
*/
|
||||||
|
exports.mysqlQuery = function (connectionString, query) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const connection = mysql.createConnection(connectionString);
|
||||||
|
connection.promise().query(query)
|
||||||
|
.then(res => {
|
||||||
|
resolve(res);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(err);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
connection.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query radius server
|
* Query radius server
|
||||||
* @param {string} hostname Hostname of radius server
|
* @param {string} hostname Hostname of radius server
|
||||||
@@ -720,3 +745,51 @@ module.exports.timeObjectToUTC = (obj, timezone = undefined) => {
|
|||||||
module.exports.timeObjectToLocal = (obj, timezone = undefined) => {
|
module.exports.timeObjectToLocal = (obj, timezone = undefined) => {
|
||||||
return timeObjectConvertTimezone(obj, timezone, false);
|
return timeObjectConvertTimezone(obj, timezone, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create gRPC client stib
|
||||||
|
* @param {Object} options from gRPC client
|
||||||
|
*/
|
||||||
|
module.exports.grpcQuery = async (options) => {
|
||||||
|
const { grpcUrl, grpcProtobufData, grpcServiceName, grpcEnableTls, grpcMethod, grpcBody } = options;
|
||||||
|
const protocObject = protojs.parse(grpcProtobufData);
|
||||||
|
const protoServiceObject = protocObject.root.lookupService(grpcServiceName);
|
||||||
|
const Client = grpc.makeGenericClientConstructor({});
|
||||||
|
const credentials = grpcEnableTls ? grpc.credentials.createSsl() : grpc.credentials.createInsecure();
|
||||||
|
const client = new Client(
|
||||||
|
grpcUrl,
|
||||||
|
credentials
|
||||||
|
);
|
||||||
|
const grpcService = protoServiceObject.create(function (method, requestData, cb) {
|
||||||
|
const fullServiceName = method.fullName;
|
||||||
|
const serviceFQDN = fullServiceName.split(".");
|
||||||
|
const serviceMethod = serviceFQDN.pop();
|
||||||
|
const serviceMethodClientImpl = `/${serviceFQDN.slice(1).join(".")}/${serviceMethod}`;
|
||||||
|
log.debug("monitor", `gRPC method ${serviceMethodClientImpl}`);
|
||||||
|
client.makeUnaryRequest(
|
||||||
|
serviceMethodClientImpl,
|
||||||
|
arg => arg,
|
||||||
|
arg => arg,
|
||||||
|
requestData,
|
||||||
|
cb);
|
||||||
|
}, false, false);
|
||||||
|
return new Promise((resolve, _) => {
|
||||||
|
return grpcService[`${grpcMethod}`](JSON.parse(grpcBody), function (err, response) {
|
||||||
|
const responseData = JSON.stringify(response);
|
||||||
|
if (err) {
|
||||||
|
return resolve({
|
||||||
|
code: err.code,
|
||||||
|
errorMessage: err.details,
|
||||||
|
data: ""
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log.debug("monitor:", `gRPC response: ${response}`);
|
||||||
|
return resolve({
|
||||||
|
code: 1,
|
||||||
|
errorMessage: "",
|
||||||
|
data: responseData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@@ -3,8 +3,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import dayjs from "dayjs";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
/** Value of date time */
|
/** Value of date time */
|
||||||
|
@@ -206,6 +206,16 @@ export default {
|
|||||||
.search-icon {
|
.search-icon {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
color: #c0c0c0;
|
color: #c0c0c0;
|
||||||
|
|
||||||
|
// Clear filter button (X)
|
||||||
|
svg[data-icon="times"] {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all ease-in-out 0.1s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
<option value="http">HTTP</option>
|
<option value="http">HTTP</option>
|
||||||
<option value="socks">SOCKS</option>
|
<option value="socks">SOCKS</option>
|
||||||
<option value="socks5">SOCKS v5</option>
|
<option value="socks5">SOCKS v5</option>
|
||||||
|
<option value="socks5h">SOCKS v5 (+DNS)</option>
|
||||||
<option value="socks4">SOCKS v4</option>
|
<option value="socks4">SOCKS v4</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -27,6 +27,10 @@
|
|||||||
<HiddenInput id="ntfy-password" v-model="$parent.notification.ntfypassword" autocomplete="new-password"></HiddenInput>
|
<HiddenInput id="ntfy-password" v-model="$parent.notification.ntfypassword" autocomplete="new-password"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="ntfy-icon" class="form-label">{{ $t("IconUrl") }}</label>
|
||||||
|
<input id="ntfy-icon" v-model="$parent.notification.ntfyIcon" type="text" class="form-control">
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
40
src/components/notifications/SMSEagle.vue
Normal file
40
src/components/notifications/SMSEagle.vue
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="smseagle-url" class="form-label">{{ $t("smseagleUrl") }}</label>
|
||||||
|
<input id="smseagle-url" v-model="$parent.notification.smseagleUrl" type="text" minlength="7" class="form-control" placeholder="http://127.0.0.1" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="smseagle-token" class="form-label">{{ $t("smseagleToken") }}</label>
|
||||||
|
<HiddenInput id="smseagle-token" v-model="$parent.notification.smseagleToken" :required="true"></HiddenInput>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="smseagle-recipient-type" class="form-label">{{ $t("smseagleRecipientType") }}</label>
|
||||||
|
<select id="smseagle-recipient-type" v-model="$parent.notification.smseagleRecipientType" class="form-select">
|
||||||
|
<option value="smseagle-to" selected>{{ $t("smseagleTo") }}</option>
|
||||||
|
<option value="smseagle-group">{{ $t("smseagleGroup") }}</option>
|
||||||
|
<option value="smseagle-contact">{{ $t("smseagleContact") }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="smseagle-recipient" class="form-label">{{ $t("smseagleRecipient") }}</label>
|
||||||
|
<input id="smseagle-recipient" v-model="$parent.notification.smseagleRecipient" type="text" class="form-control" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="smseagle-priority" class="form-label">{{ $t("smseaglePriority") }}</label>
|
||||||
|
<input id="smseagle-priority" v-model="$parent.notification.smseaglePriority" type="number" class="form-control" min="0" max="9" step="1" placeholder="0">
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 form-check form-switch">
|
||||||
|
<label for="smseagle-encoding" class="form-label">{{ $t("smseagleEncoding") }}</label>
|
||||||
|
<input id="smseagle-encoding" v-model="$parent.notification.smseagleEncoding" type="checkbox" class="form-check-input">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HiddenInput from "../HiddenInput.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HiddenInput,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@@ -1,22 +1,32 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="webhook-url" class="form-label">{{ $t("Post URL") }}</label>
|
<label for="webhook-url" class="form-label">{{ $t("Post URL") }}</label>
|
||||||
<input id="webhook-url" v-model="$parent.notification.webhookURL" type="url" pattern="https?://.+" class="form-control" required>
|
<input
|
||||||
|
id="webhook-url"
|
||||||
|
v-model="$parent.notification.webhookURL"
|
||||||
|
type="url"
|
||||||
|
pattern="https?://.+"
|
||||||
|
class="form-control"
|
||||||
|
required
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="webhook-content-type" class="form-label">{{ $t("Content Type") }}</label>
|
<label for="webhook-content-type" class="form-label">{{
|
||||||
<select id="webhook-content-type" v-model="$parent.notification.webhookContentType" class="form-select" required>
|
$t("Content Type")
|
||||||
<option value="json">
|
}}</label>
|
||||||
application/json
|
<select
|
||||||
</option>
|
id="webhook-content-type"
|
||||||
<option value="form-data">
|
v-model="$parent.notification.webhookContentType"
|
||||||
multipart/form-data
|
class="form-select"
|
||||||
</option>
|
required
|
||||||
|
>
|
||||||
|
<option value="json">application/json</option>
|
||||||
|
<option value="form-data">multipart/form-data</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
<p>{{ $t("webhookJsonDesc", ["\"application/json\""]) }}</p>
|
<p>{{ $t("webhookJsonDesc", ['"application/json"']) }}</p>
|
||||||
<i18n-t tag="p" keypath="webhookFormDataDesc">
|
<i18n-t tag="p" keypath="webhookFormDataDesc">
|
||||||
<template #multipart>"multipart/form-data"</template>
|
<template #multipart>"multipart/form-data"</template>
|
||||||
<template #decodeFunction>
|
<template #decodeFunction>
|
||||||
@@ -25,4 +35,44 @@
|
|||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<i18n-t
|
||||||
|
tag="label"
|
||||||
|
class="form-label"
|
||||||
|
for="additionalHeaders"
|
||||||
|
keypath="webhookAdditionalHeadersTitle"
|
||||||
|
>
|
||||||
|
</i18n-t>
|
||||||
|
<textarea
|
||||||
|
id="additionalHeaders"
|
||||||
|
v-model="$parent.notification.webhookAdditionalHeaders"
|
||||||
|
class="form-control"
|
||||||
|
:placeholder="headersPlaceholder"
|
||||||
|
></textarea>
|
||||||
|
<div class="form-text">
|
||||||
|
<i18n-t tag="p" keypath="webhookAdditionalHeadersDesc"> </i18n-t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
headersPlaceholder() {
|
||||||
|
return this.$t("Example:", [
|
||||||
|
`
|
||||||
|
{
|
||||||
|
"HeaderName": "HeaderValue"
|
||||||
|
}`,
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
textarea {
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -33,6 +33,7 @@ import Signal from "./Signal.vue";
|
|||||||
import SMSManager from "./SMSManager.vue";
|
import SMSManager from "./SMSManager.vue";
|
||||||
import Slack from "./Slack.vue";
|
import Slack from "./Slack.vue";
|
||||||
import Squadcast from "./Squadcast.vue";
|
import Squadcast from "./Squadcast.vue";
|
||||||
|
import SMSEagle from "./SMSEagle.vue";
|
||||||
import Stackfield from "./Stackfield.vue";
|
import Stackfield from "./Stackfield.vue";
|
||||||
import STMP from "./SMTP.vue";
|
import STMP from "./SMTP.vue";
|
||||||
import Teams from "./Teams.vue";
|
import Teams from "./Teams.vue";
|
||||||
@@ -83,6 +84,7 @@ const NotificationFormList = {
|
|||||||
"SMSManager": SMSManager,
|
"SMSManager": SMSManager,
|
||||||
"slack": Slack,
|
"slack": Slack,
|
||||||
"squadcast": Squadcast,
|
"squadcast": Squadcast,
|
||||||
|
"SMSEagle": SMSEagle,
|
||||||
"smtp": STMP,
|
"smtp": STMP,
|
||||||
"stackfield": Stackfield,
|
"stackfield": Stackfield,
|
||||||
"teams": Teams,
|
"teams": Teams,
|
||||||
|
@@ -1,13 +1,14 @@
|
|||||||
# How to translate
|
# How to translate
|
||||||
|
|
||||||
1. Fork this repo.
|
1. Fork this repo.
|
||||||
2. Run `npm run update-language-files --language=<code>` where `<code>`
|
2. Run `npm install`
|
||||||
|
3. Run `npm run update-language-files --language=<code>` where `<code>`
|
||||||
is a valid ISO language code:
|
is a valid ISO language code:
|
||||||
http://www.lingoes.net/en/translator/langcode.htm. You can also use
|
http://www.lingoes.net/en/translator/langcode.htm. You can also use
|
||||||
this command to check if there are new strings to
|
this command to check if there are new strings to
|
||||||
translate for your language.
|
translate for your language.
|
||||||
3. Your language file should be filled in. You can translate now.
|
4. Your language file should be filled in. You can translate now.
|
||||||
4. Add it into `languageList` constant.
|
5. Add it into `languageList` constant.
|
||||||
5. Make a [pull request](https://github.com/louislam/uptime-kuma/pulls) when you have done.
|
6. Make a [pull request](https://github.com/louislam/uptime-kuma/pulls) when you have done.
|
||||||
|
|
||||||
If you do not have programming skills, let me know in [the issues section](https://github.com/louislam/uptime-kuma/issues). I will assist you. 😏
|
If you do not have programming skills, let me know in [the issues section](https://github.com/louislam/uptime-kuma/issues). I will assist you. 😏
|
||||||
|
@@ -582,4 +582,66 @@ export default {
|
|||||||
goAlert: "GoAlert",
|
goAlert: "GoAlert",
|
||||||
backupOutdatedWarning: "Отпаднало: Тъй като са добавени много функции, тази опция за архивиране не е достатъчно поддържана и не може да генерира или възстанови пълен архив.",
|
backupOutdatedWarning: "Отпаднало: Тъй като са добавени много функции, тази опция за архивиране не е достатъчно поддържана и не може да генерира или възстанови пълен архив.",
|
||||||
backupRecommend: "Моля, архивирайте дяла или папката (./data/) директно вместо това.",
|
backupRecommend: "Моля, архивирайте дяла или папката (./data/) директно вместо това.",
|
||||||
|
Maintenance: "Поддръжка",
|
||||||
|
statusMaintenance: "Поддръжка",
|
||||||
|
"Schedule maintenance": "Планиране на поддръжка",
|
||||||
|
"Affected Monitors": "Засегнати монитори",
|
||||||
|
"Pick Affected Monitors...": "Изберете засегнати монитори...",
|
||||||
|
"Start of maintenance": "Стартирай поддръжка",
|
||||||
|
"All Status Pages": "Всички статус страници",
|
||||||
|
"Select status pages...": "Изберете статус страници...",
|
||||||
|
recurringIntervalMessage: "Изпълнявай ежедневно | Изпълнявай всеки {0} дни",
|
||||||
|
affectedMonitorsDescription: "Изберете монитори, засегнати от текущата поддръжка",
|
||||||
|
affectedStatusPages: "Покажи това съобщение за поддръжка на избрани статус страници",
|
||||||
|
atLeastOneMonitor: "Изберете поне един засегнат монитор",
|
||||||
|
deleteMaintenanceMsg: "Сигурни ли сте, че желаете да изтриете тази поддръжка?",
|
||||||
|
Optional: "По желание",
|
||||||
|
squadcast: "Squadcast",
|
||||||
|
SendKey: "SendKey",
|
||||||
|
"SMSManager API Docs": "SMSManager API Документация ",
|
||||||
|
"Gateway Type": "Тип на шлюза",
|
||||||
|
SMSManager: "SMSManager",
|
||||||
|
"You can divide numbers with": "Може да разделяте числата с",
|
||||||
|
or: "или",
|
||||||
|
recurringInterval: "Интервал",
|
||||||
|
Recurring: "Повтаряне",
|
||||||
|
strategyManual: "Активен/Неактивен ръчно",
|
||||||
|
warningTimezone: "Използва се часовата зона на сървъра",
|
||||||
|
weekdayShortMon: "Пон",
|
||||||
|
weekdayShortTue: "Вт",
|
||||||
|
weekdayShortWed: "Ср",
|
||||||
|
weekdayShortThu: "Чет",
|
||||||
|
weekdayShortFri: "Пет",
|
||||||
|
weekdayShortSat: "Съб",
|
||||||
|
weekdayShortSun: "Нед",
|
||||||
|
dayOfWeek: "Ден",
|
||||||
|
dayOfMonth: "Дата",
|
||||||
|
lastDay: "Последен ден",
|
||||||
|
lastDay1: "Последен ден от месеца",
|
||||||
|
lastDay2: "2-ри последен ден на месеца",
|
||||||
|
lastDay3: "3-ти последен ден на месеца",
|
||||||
|
lastDay4: "4-ти последен ден на месеца",
|
||||||
|
"No Maintenance": "Няма поддръжка",
|
||||||
|
pauseMaintenanceMsg: "Сигурни ли сте, че желаете да направите пауза?",
|
||||||
|
"maintenanceStatus-under-maintenance": "В режим поддръжка",
|
||||||
|
"maintenanceStatus-inactive": "Неактивна",
|
||||||
|
"maintenanceStatus-scheduled": "Планирана",
|
||||||
|
"maintenanceStatus-ended": "Приключена",
|
||||||
|
"maintenanceStatus-unknown": "Неизвестна",
|
||||||
|
"Display Timezone": "Покажи часова зона",
|
||||||
|
"Server Timezone": "Часова зона на сървъра",
|
||||||
|
statusPageMaintenanceEndDate: "Край",
|
||||||
|
enableGRPCTls: "Разреши изпращане на gRPC заявка с TLS връзка",
|
||||||
|
grpcMethodDescription: "Името на метода се форматира в \"cammelCase\", например sayHello, check, и т.н.",
|
||||||
|
smseagle: "SMSEagle",
|
||||||
|
smseagleTo: "Тел. номер(а)",
|
||||||
|
smseagleGroup: "Име на група/и от тел. указател",
|
||||||
|
smseagleContact: "Име(на) от тел. указател",
|
||||||
|
smseagleRecipientType: "Получател тип",
|
||||||
|
smseagleRecipient: "Получател(и) (при повече от един разделете със запетая)",
|
||||||
|
smseagleToken: "API токен за достъп",
|
||||||
|
smseagleUrl: "Вашият SMSEagle URL на устройството",
|
||||||
|
smseagleEncoding: "Изпрати като Unicode",
|
||||||
|
smseaglePriority: "Приоритет на съобщението (0-9, по подразбиране = 0)",
|
||||||
|
IconUrl: "Икона URL адрес",
|
||||||
};
|
};
|
||||||
|
@@ -576,4 +576,59 @@ export default {
|
|||||||
"Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.",
|
"Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.",
|
||||||
"Frontend Version": "Frontend Version",
|
"Frontend Version": "Frontend Version",
|
||||||
"Frontend Version do not match backend version!": "Die Frontend Version stimmt nicht mit der backend version überein!",
|
"Frontend Version do not match backend version!": "Die Frontend Version stimmt nicht mit der backend version überein!",
|
||||||
|
Maintenance: "Wartung",
|
||||||
|
statusMaintenance: "Wartung",
|
||||||
|
"Schedule maintenance": "Geplante Wartung",
|
||||||
|
"Affected Monitors": "Betroffene Monitore",
|
||||||
|
"Pick Affected Monitors...": "Wähle betroffene Monitore...",
|
||||||
|
"Start of maintenance": "Beginn der Wartung",
|
||||||
|
"All Status Pages": "Alle Status Seiten",
|
||||||
|
"Select status pages...": "Wähle Status Seiten...",
|
||||||
|
recurringIntervalMessage: "einmal pro Tag ausgeführt | Wird alle {0} Tage ausgführt",
|
||||||
|
affectedMonitorsDescription: "Wähle alle Monitore die von der Wartung betroffen sind",
|
||||||
|
affectedStatusPages: "Zeige diese Nachricht auf ausgewählten Status Seiten",
|
||||||
|
atLeastOneMonitor: "Wähle mindestens einen Monitor",
|
||||||
|
deleteMaintenanceMsg: "Möchtest du diese Wartung löschen?",
|
||||||
|
"Base URL": "Basis URL",
|
||||||
|
goAlertInfo: "GoAlert ist eine Open-Source Applikation für Rufbereitschaft Planung, automaitsche Esklaltion und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt! {0}",
|
||||||
|
goAlertIntegrationKeyInfo: "Bekomm einenen gernerischen API Schlüssel in folgeden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise der Wert des Token aus der URL.",
|
||||||
|
goAlert: "GoAlert",
|
||||||
|
backupOutdatedWarning: "Veraltet: Eine menge Neuerungen sind eingeflossen und diese Funktion wurde etwas vernachlässigt worden. Es kann kein vollständiges Backup erstellt oder eingspielt werden.",
|
||||||
|
backupRecommend: "Bitte Backup das Volume oder den Ordner (./ data /) selbst.",
|
||||||
|
Optional: "Optional",
|
||||||
|
squadcast: "Squadcast",
|
||||||
|
SendKey: "SendKey",
|
||||||
|
"SMSManager API Docs": "SMSManager API Dokumente",
|
||||||
|
"Gateway Type": "Gateway Type",
|
||||||
|
SMSManager: "SMSManager",
|
||||||
|
"You can divide numbers with": "Du kannst Zahlen teilen mit",
|
||||||
|
or: "oder",
|
||||||
|
recurringInterval: "Intervall",
|
||||||
|
Recurring: "Wiederkehrend",
|
||||||
|
strategyManual: "Active/Inactive Manually",
|
||||||
|
warningTimezone: "Es wird die Zeitzone des Servers genutzt",
|
||||||
|
weekdayShortMon: "Mo",
|
||||||
|
weekdayShortTue: "Di",
|
||||||
|
weekdayShortWed: "Mi",
|
||||||
|
weekdayShortThu: "Do",
|
||||||
|
weekdayShortFri: "Fr",
|
||||||
|
weekdayShortSat: "Sa",
|
||||||
|
weekdayShortSun: "So",
|
||||||
|
dayOfWeek: "Tag der Woche",
|
||||||
|
dayOfMonth: "Tag im Monat",
|
||||||
|
lastDay: "Letzter Tag",
|
||||||
|
lastDay1: "Letzter Tag im Monat",
|
||||||
|
lastDay2: "Vorletzer Tag im Monat",
|
||||||
|
lastDay3: "3. letzter Tag im Monat",
|
||||||
|
lastDay4: "4. letzter Tag im Monat",
|
||||||
|
"No Maintenance": "Keine Wartung",
|
||||||
|
pauseMaintenanceMsg: "Möchtest du wirklich pausieren?",
|
||||||
|
"maintenanceStatus-under-maintenance": "Unter Wartung",
|
||||||
|
"maintenanceStatus-inactive": "Inaktiv",
|
||||||
|
"maintenanceStatus-scheduled": "Geplant",
|
||||||
|
"maintenanceStatus-ended": "Ende",
|
||||||
|
"maintenanceStatus-unknown": "Unbekannt",
|
||||||
|
"Display Timezone": "Zeitzone anzeigen",
|
||||||
|
"Server Timezone": "Server Zeitzone",
|
||||||
|
statusPageMaintenanceEndDate: "Ende",
|
||||||
};
|
};
|
||||||
|
@@ -8,6 +8,8 @@ export default {
|
|||||||
ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
|
ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
|
||||||
upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
|
upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
|
||||||
maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
|
maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
|
||||||
|
enableGRPCTls: "Allow to send gRPC request with TLS connection",
|
||||||
|
grpcMethodDescription: "Method name is convert to cammelCase format such as sayHello, check, etc.",
|
||||||
acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
|
acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
|
||||||
Maintenance: "Maintenance",
|
Maintenance: "Maintenance",
|
||||||
statusMaintenance: "Maintenance",
|
statusMaintenance: "Maintenance",
|
||||||
@@ -219,6 +221,8 @@ export default {
|
|||||||
"Content Type": "Content Type",
|
"Content Type": "Content Type",
|
||||||
webhookJsonDesc: "{0} is good for any modern HTTP servers such as Express.js",
|
webhookJsonDesc: "{0} is good for any modern HTTP servers such as Express.js",
|
||||||
webhookFormDataDesc: "{multipart} is good for PHP. The JSON will need to be parsed with {decodeFunction}",
|
webhookFormDataDesc: "{multipart} is good for PHP. The JSON will need to be parsed with {decodeFunction}",
|
||||||
|
webhookAdditionalHeadersTitle: "Additional Headers",
|
||||||
|
webhookAdditionalHeadersDesc: "Sets additional headers sent with the webhook.",
|
||||||
smtp: "Email (SMTP)",
|
smtp: "Email (SMTP)",
|
||||||
secureOptionNone: "None / STARTTLS (25, 587)",
|
secureOptionNone: "None / STARTTLS (25, 587)",
|
||||||
secureOptionTLS: "TLS (465)",
|
secureOptionTLS: "TLS (465)",
|
||||||
@@ -378,6 +382,16 @@ export default {
|
|||||||
serwersmsAPIPassword: "API Password",
|
serwersmsAPIPassword: "API Password",
|
||||||
serwersmsPhoneNumber: "Phone number",
|
serwersmsPhoneNumber: "Phone number",
|
||||||
serwersmsSenderName: "SMS Sender Name (registered via customer portal)",
|
serwersmsSenderName: "SMS Sender Name (registered via customer portal)",
|
||||||
|
smseagle: "SMSEagle",
|
||||||
|
smseagleTo: "Phone number(s)",
|
||||||
|
smseagleGroup: "Phonebook group name(s)",
|
||||||
|
smseagleContact: "Phonebook contact name(s)",
|
||||||
|
smseagleRecipientType: "Recipient type",
|
||||||
|
smseagleRecipient: "Recipient(s) (multiple must be separated with comma)",
|
||||||
|
smseagleToken: "API Access token",
|
||||||
|
smseagleUrl: "Your SMSEagle device URL",
|
||||||
|
smseagleEncoding: "Send as Unicode",
|
||||||
|
smseaglePriority: "Message priority (0-9, default = 0)",
|
||||||
stackfield: "Stackfield",
|
stackfield: "Stackfield",
|
||||||
Customize: "Customize",
|
Customize: "Customize",
|
||||||
"Custom Footer": "Custom Footer",
|
"Custom Footer": "Custom Footer",
|
||||||
@@ -631,4 +645,5 @@ export default {
|
|||||||
"Display Timezone": "Display Timezone",
|
"Display Timezone": "Display Timezone",
|
||||||
"Server Timezone": "Server Timezone",
|
"Server Timezone": "Server Timezone",
|
||||||
statusPageMaintenanceEndDate: "End",
|
statusPageMaintenanceEndDate: "End",
|
||||||
|
IconUrl: "Icon URL",
|
||||||
};
|
};
|
||||||
|
@@ -531,4 +531,57 @@ export default {
|
|||||||
backupRecommend: "Veuillez sauvegarder le volume ou le dossier de données (./data/) directement à la place.",
|
backupRecommend: "Veuillez sauvegarder le volume ou le dossier de données (./data/) directement à la place.",
|
||||||
Optional: "Optionnel",
|
Optional: "Optionnel",
|
||||||
squadcast: "Squadcast",
|
squadcast: "Squadcast",
|
||||||
|
Maintenance: "Maintenance",
|
||||||
|
statusMaintenance: "Maintenance",
|
||||||
|
"Schedule maintenance": "Planifier la maintenance",
|
||||||
|
"Affected Monitors": "Moniteurs concernés",
|
||||||
|
"Pick Affected Monitors...": "Sélectionnez les moniteurs concernés...",
|
||||||
|
"Start of maintenance": "Début de la maintenance",
|
||||||
|
"All Status Pages": "Toutes les pages d'état",
|
||||||
|
"Select status pages...": "Sélectionnez les pages d'état...",
|
||||||
|
recurringIntervalMessage: "Exécuter une fois par jour | Exécuter une fois tous les {0} jours",
|
||||||
|
affectedMonitorsDescription: "Sélectionnez les moniteurs concernés par la maintenance en cours",
|
||||||
|
affectedStatusPages: "Afficher ce message de maintenance sur les pages d'état sélectionnées",
|
||||||
|
atLeastOneMonitor: "Sélectionnez au moins un moniteur concerné",
|
||||||
|
deleteMaintenanceMsg: "Voulez-vous vraiment supprimer cette maintenance ?",
|
||||||
|
pushyAPIKey: "Clé API secrète",
|
||||||
|
pushyToken: "Jeton d'appareil",
|
||||||
|
"You can divide numbers with": "Vous pouvez diviser des nombres avec",
|
||||||
|
or: "ou",
|
||||||
|
recurringInterval: "Intervalle",
|
||||||
|
Recurring: "Récurrent",
|
||||||
|
"Single Maintenance Window": "Fenêtre de maintenance unique",
|
||||||
|
"Maintenance Time Window of a Day": "Fenêtre de temps de maintenance",
|
||||||
|
"Effective Date Range": "Plage de dates d'effet",
|
||||||
|
strategyManual: "activer/desactiver manuellement",
|
||||||
|
warningTimezone: "Il utilise le fuseau horaire du serveur",
|
||||||
|
weekdayShortMon: "Lun",
|
||||||
|
weekdayShortTue: "Mar",
|
||||||
|
weekdayShortWed: "Mer",
|
||||||
|
weekdayShortThu: "Jeu",
|
||||||
|
weekdayShortFri: "Ven",
|
||||||
|
weekdayShortSat: "Sam",
|
||||||
|
weekdayShortSun: "Dim",
|
||||||
|
dayOfWeek: "Jour de la semaine",
|
||||||
|
dayOfMonth: "Jour du mois",
|
||||||
|
lastDay: "Dernier jour",
|
||||||
|
lastDay1: "Dernier jour du mois",
|
||||||
|
lastDay2: "2ème dernier jour du mois",
|
||||||
|
lastDay3: "3ème dernier jour du mois",
|
||||||
|
lastDay4: "4ème dernier jour du mois",
|
||||||
|
"No Maintenance": "Aucune Maintenance",
|
||||||
|
pauseMaintenanceMsg: "Voulez-vous vraiment mettre en pause ?",
|
||||||
|
"maintenanceStatus-under-maintenance": "En maintenance",
|
||||||
|
"maintenanceStatus-inactive": "Inactif",
|
||||||
|
"maintenanceStatus-scheduled": "Programmé",
|
||||||
|
"maintenanceStatus-ended": "Terminé",
|
||||||
|
"maintenanceStatus-unknown": "Inconnue",
|
||||||
|
"Display Timezone": "Afficher le fuseau horaire",
|
||||||
|
"Server Timezone": "Fuseau horaire du serveur",
|
||||||
|
"Date and Time": "Date et heure",
|
||||||
|
"DateTime Range": "Plage de dates et d'heures",
|
||||||
|
Strategy: "Stratégie",
|
||||||
|
statusPageMaintenanceEndDate: "Fin",
|
||||||
|
"Free Mobile User Identifier": "Identifiant d'utilisateur Free Mobile",
|
||||||
|
"Free Mobile API Key": "Clé API Free Mobile",
|
||||||
};
|
};
|
||||||
|
@@ -27,8 +27,8 @@ export default {
|
|||||||
confirmImportMsg: "Apakah Anda yakin untuk mengimpor cadangan? Pastikan Anda telah memilih opsi impor yang tepat.",
|
confirmImportMsg: "Apakah Anda yakin untuk mengimpor cadangan? Pastikan Anda telah memilih opsi impor yang tepat.",
|
||||||
twoFAVerifyLabel: "Silakan ketik token Anda untuk memverifikasi bahwa 2FA berfungsi",
|
twoFAVerifyLabel: "Silakan ketik token Anda untuk memverifikasi bahwa 2FA berfungsi",
|
||||||
tokenValidSettingsMsg: "Token benar! Anda sekarang dapat menyimpan pengaturan 2FA.",
|
tokenValidSettingsMsg: "Token benar! Anda sekarang dapat menyimpan pengaturan 2FA.",
|
||||||
confirmEnableTwoFAMsg: "Apakah anda yakin ingin mengaktifkan 2FA?",
|
confirmEnableTwoFAMsg: "Apakah Anda yakin ingin mengaktifkan 2FA?",
|
||||||
confirmDisableTwoFAMsg: "Apakah anda yakin ingin menonaktifkan 2FA?",
|
confirmDisableTwoFAMsg: "Apakah Anda yakin ingin menonaktifkan 2FA?",
|
||||||
Settings: "Pengaturan",
|
Settings: "Pengaturan",
|
||||||
Dashboard: "Dasbor",
|
Dashboard: "Dasbor",
|
||||||
"New Update": "Pembaruan Baru",
|
"New Update": "Pembaruan Baru",
|
||||||
@@ -126,7 +126,7 @@ export default {
|
|||||||
"Resolver Server": "Resolver Server",
|
"Resolver Server": "Resolver Server",
|
||||||
"Resource Record Type": "Resource Record Type",
|
"Resource Record Type": "Resource Record Type",
|
||||||
"Last Result": "Hasil Terakhir",
|
"Last Result": "Hasil Terakhir",
|
||||||
"Create your admin account": "Buat akun admin anda",
|
"Create your admin account": "Buat akun admin Anda",
|
||||||
"Repeat Password": "Ulangi Sandi",
|
"Repeat Password": "Ulangi Sandi",
|
||||||
"Import Backup": "Impor Cadangan",
|
"Import Backup": "Impor Cadangan",
|
||||||
"Export Backup": "Ekspor Cadangan",
|
"Export Backup": "Ekspor Cadangan",
|
||||||
|
@@ -125,7 +125,7 @@ export default {
|
|||||||
Export: "Eksportuj",
|
Export: "Eksportuj",
|
||||||
Import: "Importuj",
|
Import: "Importuj",
|
||||||
respTime: "Czas odp. (ms)",
|
respTime: "Czas odp. (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/D",
|
||||||
"Default enabled": "Włącz domyślnie",
|
"Default enabled": "Włącz domyślnie",
|
||||||
"Apply on all existing monitors": "Zastosuj do istniejących monitorów",
|
"Apply on all existing monitors": "Zastosuj do istniejących monitorów",
|
||||||
Create: "Stwórz",
|
Create: "Stwórz",
|
||||||
@@ -181,7 +181,7 @@ export default {
|
|||||||
"Edit Status Page": "Edytuj stronę statusu",
|
"Edit Status Page": "Edytuj stronę statusu",
|
||||||
"Go to Dashboard": "Idź do panelu",
|
"Go to Dashboard": "Idź do panelu",
|
||||||
"Status Page": "Strona statusu",
|
"Status Page": "Strona statusu",
|
||||||
"Status Pages": "Strona statusu",
|
"Status Pages": "Strony statusów",
|
||||||
defaultNotificationName: "Moje powiadomienie {notification} ({number})",
|
defaultNotificationName: "Moje powiadomienie {notification} ({number})",
|
||||||
here: "tutaj",
|
here: "tutaj",
|
||||||
Required: "Wymagane",
|
Required: "Wymagane",
|
||||||
@@ -359,6 +359,16 @@ export default {
|
|||||||
serwersmsAPIPassword: "Hasło API",
|
serwersmsAPIPassword: "Hasło API",
|
||||||
serwersmsPhoneNumber: "Numer telefonu",
|
serwersmsPhoneNumber: "Numer telefonu",
|
||||||
serwersmsSenderName: "Nazwa nadawcy (zatwierdzona w panelu klienta)",
|
serwersmsSenderName: "Nazwa nadawcy (zatwierdzona w panelu klienta)",
|
||||||
|
smseagle: "SMSEagle",
|
||||||
|
smseagleTo: "Numer/y telefonu",
|
||||||
|
smseagleGroup: "Grupa/y z Książki adresowej",
|
||||||
|
smseagleContact: "Kontakt/y z Książki adresowej",
|
||||||
|
smseagleRecipientType: "Typ odbiorcy",
|
||||||
|
smseagleRecipient: "Odbiorca/y (wiele musi być oddzielone przecinkami)",
|
||||||
|
smseagleToken: "Klucz dostępu API",
|
||||||
|
smseagleUrl: "URL Twojego urządzenia SMSEagle",
|
||||||
|
smseagleEncoding: "Wyślij jako Unicode",
|
||||||
|
smseaglePriority: "Priorytet wiadomości (0-9, domyślnie = 0)",
|
||||||
stackfield: "Stackfield",
|
stackfield: "Stackfield",
|
||||||
Customize: "Dostosuj",
|
Customize: "Dostosuj",
|
||||||
"Custom Footer": "Niestandardowa stopka",
|
"Custom Footer": "Niestandardowa stopka",
|
||||||
@@ -435,7 +445,7 @@ export default {
|
|||||||
"HTTP Basic Auth": "Podstawowa autoryzacja HTTP",
|
"HTTP Basic Auth": "Podstawowa autoryzacja HTTP",
|
||||||
"New Status Page": "Nowa strona statusu",
|
"New Status Page": "Nowa strona statusu",
|
||||||
"Page Not Found": "Strona nie została znaleziona",
|
"Page Not Found": "Strona nie została znaleziona",
|
||||||
"Reverse Proxy": "Odwrotne Proxy",
|
"Reverse Proxy": "Zwrotny serwer proxy",
|
||||||
Backup: "Backup",
|
Backup: "Backup",
|
||||||
About: "O skrypcie",
|
About: "O skrypcie",
|
||||||
wayToGetCloudflaredURL: "(Pobierz cloudflared z {0})",
|
wayToGetCloudflaredURL: "(Pobierz cloudflared z {0})",
|
||||||
@@ -447,7 +457,7 @@ export default {
|
|||||||
"For example: nginx, Apache and Traefik.": "Na przykład: nginx, Apache i Traefik.",
|
"For example: nginx, Apache and Traefik.": "Na przykład: nginx, Apache i Traefik.",
|
||||||
"Please read": "Przeczytaj proszę",
|
"Please read": "Przeczytaj proszę",
|
||||||
"Subject:": "Temat:",
|
"Subject:": "Temat:",
|
||||||
"Valid To:": "Ważdny do:",
|
"Valid To:": "Ważny do:",
|
||||||
"Days Remaining:": "Pozostało dni:",
|
"Days Remaining:": "Pozostało dni:",
|
||||||
"Issuer:": "Wydawca:",
|
"Issuer:": "Wydawca:",
|
||||||
"Fingerprint:": "Odcisk palca:",
|
"Fingerprint:": "Odcisk palca:",
|
||||||
@@ -467,4 +477,168 @@ export default {
|
|||||||
"Domain Names": "Domeny",
|
"Domain Names": "Domeny",
|
||||||
signedInDisp: "Zalogowany jako {0}",
|
signedInDisp: "Zalogowany jako {0}",
|
||||||
signedInDispDisabled: "Autoryzacja wyłączona.",
|
signedInDispDisabled: "Autoryzacja wyłączona.",
|
||||||
|
resendEveryXTimes: "Wysyłaj ponownie co {0} razy",
|
||||||
|
resendDisabled: "Ponowne wysyłanie jest wyłączone",
|
||||||
|
Maintenance: "Konserwacja",
|
||||||
|
statusMaintenance: "Konserwacja",
|
||||||
|
"Schedule maintenance": "Planowanie konserwacji",
|
||||||
|
"Affected Monitors": "Monitory dotknięte problemem",
|
||||||
|
"Pick Affected Monitors...": "Wybierz monitory, których to dotyczy...",
|
||||||
|
"Start of maintenance": "Rozpoczęcie konserwacji",
|
||||||
|
"All Status Pages": "Wszystkie strony statusu",
|
||||||
|
"Select status pages...": "Wybierz strony statusu...",
|
||||||
|
recurringIntervalMessage: "Uruchom raz dziennie | Uruchom raz na {0} dni",
|
||||||
|
affectedMonitorsDescription: "Wybierz monitory, których dotyczy bieżąca konserwacja",
|
||||||
|
affectedStatusPages: "Pokaż ten komunikat o konserwacji na wybranych stronach statusu",
|
||||||
|
atLeastOneMonitor: "Wybierz co najmniej jeden monitor, którego dotyczy problem",
|
||||||
|
deleteMaintenanceMsg: "Czy na pewno chcesz usunąć tę konserwację?",
|
||||||
|
dnsPortDescription: "Port serwera DNS. Domyślnie 53. Możesz zmienić port w dowolnym momencie.",
|
||||||
|
"Resend Notification if Down X times consequently": "Wyślij ponownie powiadomienie, jeśli nie działa X razy pod rząd",
|
||||||
|
error: "błąd",
|
||||||
|
critical: "krytyczny",
|
||||||
|
wayToGetPagerDutyKey: "Możesz to uzyskać, przechodząc do Service -> Service Directory -> (wybierz usługę) -> Integrations -> Add integration. Tutaj możesz wyszukać \"Events API V2\". Więcej informacji {0}",
|
||||||
|
"Integration Key": "Klucz integracji",
|
||||||
|
"Integration URL": "Adres URL integracji",
|
||||||
|
"Auto resolve or acknowledged": "Automatycznie rozwiązany lub potwierdzony",
|
||||||
|
"do nothing": "nie rób nic",
|
||||||
|
"auto acknowledged": "auto potwierdzony",
|
||||||
|
"auto resolve": "automatycznie rozwiązany",
|
||||||
|
"Bark Group": "Grupa Bark",
|
||||||
|
"Bark Sound": "Dźwięk Bark",
|
||||||
|
"HTTP Headers": "Nagłówki HTTP",
|
||||||
|
"Trust Proxy": "Ufaj proxy",
|
||||||
|
HomeAssistant: "Home Assistant",
|
||||||
|
RadiusSecret: "Sekretny klucz Radius",
|
||||||
|
RadiusSecretDescription: "Współdzielony sekretny klucz pomiędzy klientem a serwerem",
|
||||||
|
RadiusCalledStationId: "Id stacji wywoływanej",
|
||||||
|
RadiusCalledStationIdDescription: "Identyfikator wywoływanego urządzenia",
|
||||||
|
RadiusCallingStationId: "Id stacji wywoławczej",
|
||||||
|
RadiusCallingStationIdDescription: "Identyfikator urządzenia wywołującego",
|
||||||
|
"Certificate Expiry Notification": "Powiadomienie o wygaśnięciu certyfikatu",
|
||||||
|
"API Username": "Nazwa użytkownika API",
|
||||||
|
"API Key": "Klucz API",
|
||||||
|
"Recipient Number": "Numer odbiorcy",
|
||||||
|
"From Name/Number": "Od nazwa/numer",
|
||||||
|
"Leave blank to use a shared sender number.": "Pozostaw puste, aby użyć wspólnego numeru nadawcy.",
|
||||||
|
"Octopush API Version": "Wersja API Octopush",
|
||||||
|
"Legacy Octopush-DM": "Starsze Octopush-DM",
|
||||||
|
endpoint: "punkt końcowy",
|
||||||
|
octopushAPIKey: "\"API key\" z poświadczeń HTTP API w panelu sterowania",
|
||||||
|
octopushLogin: "\"Login\" z poświadczeń HTTP API w panelu sterowania",
|
||||||
|
promosmsLogin: "Nazwa logowania API",
|
||||||
|
promosmsPassword: "Hasło API",
|
||||||
|
"pushoversounds pushover": "Pushover (domyślny)",
|
||||||
|
"pushoversounds bike": "Bike",
|
||||||
|
"pushoversounds bugle": "Bugle",
|
||||||
|
"pushoversounds cashregister": "Cash Register",
|
||||||
|
"pushoversounds classical": "Classical",
|
||||||
|
"pushoversounds cosmic": "Cosmic",
|
||||||
|
"pushoversounds falling": "Falling",
|
||||||
|
"pushoversounds gamelan": "Gamelan",
|
||||||
|
"pushoversounds incoming": "Incoming",
|
||||||
|
"pushoversounds intermission": "Intermission",
|
||||||
|
"pushoversounds magic": "Magic",
|
||||||
|
"pushoversounds mechanical": "Mechanical",
|
||||||
|
"pushoversounds pianobar": "Piano Bar",
|
||||||
|
"pushoversounds siren": "Siren",
|
||||||
|
"pushoversounds spacealarm": "Space Alarm",
|
||||||
|
"pushoversounds tugboat": "Tug Boat",
|
||||||
|
"pushoversounds alien": "Alien Alarm (długie)",
|
||||||
|
"pushoversounds climb": "Climb (długie)",
|
||||||
|
"pushoversounds persistent": "Persistent (długie)",
|
||||||
|
"pushoversounds echo": "Pushover Echo (długie)",
|
||||||
|
"pushoversounds updown": "Up Down (długie)",
|
||||||
|
"pushoversounds vibrate": "Tylko wibracje",
|
||||||
|
"pushoversounds none": "Brak (cisza)",
|
||||||
|
pushyAPIKey: "Tajny klucz API",
|
||||||
|
pushyToken: "Token urządzenia",
|
||||||
|
"Show update if available": "Pokaż aktualizację, jeśli jest dostępna",
|
||||||
|
"Also check beta release": "Sprawdź również wydanie beta",
|
||||||
|
"Using a Reverse Proxy?": "Używasz odwróconego proxy?",
|
||||||
|
"Check how to config it for WebSocket": "Sprawdź jak go skonfigurować dla WebSocket",
|
||||||
|
"Steam Game Server": "Serwer gry Steam",
|
||||||
|
"Most likely causes:": "Najbardziej prawdopodobne przyczyny:",
|
||||||
|
"The resource is no longer available.": "Zasób nie jest już dostępny.",
|
||||||
|
"There might be a typing error in the address.": "W adresie może być błąd w pisowni.",
|
||||||
|
"What you can try:": "Co możesz spróbować:",
|
||||||
|
"Retype the address.": "Ponownie wpisz adres.",
|
||||||
|
"Go back to the previous page.": "Wróć do poprzedniej strony.",
|
||||||
|
"Coming Soon": "Wkrótce",
|
||||||
|
wayToGetClickSendSMSToken: "Możesz uzyskać nazwę użytkownika API i klucz API z {0}.",
|
||||||
|
"Connection String": "Ciąg połączenia",
|
||||||
|
Query: "Zapytanie",
|
||||||
|
settingsCertificateExpiry: "Wygaśnięcie certyfikatu TLS",
|
||||||
|
certificationExpiryDescription: "Monitory HTTPS uruchamiają powiadomienia o wygaśnięciu certyfikatu TLS w:",
|
||||||
|
"Setup Docker Host": "Konfiguracja hosta Docker",
|
||||||
|
"Connection Type": "Typ połączenia",
|
||||||
|
"Docker Daemon": "Demon Dockera",
|
||||||
|
deleteDockerHostMsg: "Czy na pewno chcesz usunąć ten host Dockera dla wszystkich monitorów?",
|
||||||
|
socket: "Gniazdo",
|
||||||
|
tcp: "TCP / HTTP",
|
||||||
|
"Docker Container": "Kontener Dockera",
|
||||||
|
"Container Name / ID": "Nazwa kontenera / ID",
|
||||||
|
"Docker Host": "Host Dockera",
|
||||||
|
"Docker Hosts": "Hosty Dockera",
|
||||||
|
"ntfy Topic": "Temat ntfy",
|
||||||
|
Domain: "Domena",
|
||||||
|
Workstation: "Stacja robocza",
|
||||||
|
disableCloudflaredNoAuthMsg: "Jesteś w trybie No Auth, hasło nie jest wymagane.",
|
||||||
|
trustProxyDescription: "Zaufaj nagłówkom 'X-Forwarded-*'. Jeśli chcesz uzyskać poprawne IP klienta, a twój Uptime Kuma jest za Nginx lub Apache, powinieneś to włączyć.",
|
||||||
|
wayToGetLineNotifyToken: "Możesz uzyskać token dostępu z {0}",
|
||||||
|
Examples: "Przykłady",
|
||||||
|
"Home Assistant URL": "URL Home Assistant",
|
||||||
|
"Long-Lived Access Token": "Długotrwały token dostępu",
|
||||||
|
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Długotrwały token dostępu można utworzyć klikając na nazwę swojego profilu (na dole po lewej stronie) i przewijając do dołu, a następnie klikając Create Token. ",
|
||||||
|
"Notification Service": "Usługa powiadamiania",
|
||||||
|
"default: notify all devices": "domyślnie: powiadamiaj wszystkie urządzenia",
|
||||||
|
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Listę usług powiadamiania można znaleźć w Home Assistant pod \"Developer Tools > Services\" wyszukaj \"notification\", aby znaleźć nazwę swojego urządzenia/telefonu.",
|
||||||
|
"Automations can optionally be triggered in Home Assistant:": "Automaty mogą być opcjonalnie uruchamiane w Home Assistant:",
|
||||||
|
"Trigger type:": "Typ wyzwalacza:",
|
||||||
|
"Event type:": "Typ zdarzenia:",
|
||||||
|
"Event data:": "Dane o zdarzeniu:",
|
||||||
|
"Then choose an action, for example switch the scene to where an RGB light is red.": "Następnie wybierz akcję, na przykład przełącz scenę na taką, w której światło RGB jest czerwone.",
|
||||||
|
"Frontend Version": "Wersja frontu",
|
||||||
|
"Frontend Version do not match backend version!": "Wersja frontu nie pasuje do wersji backendu!",
|
||||||
|
"Base URL": "Bazowy adres URL",
|
||||||
|
goAlertInfo: "GoAlert to aplikacja open source do planowania, automatycznych eskalacji i powiadomień (jak SMS lub połączenia głosowe). Automatycznie angażuj właściwą osobę, we właściwy sposób i we właściwym czasie! {0}",
|
||||||
|
goAlertIntegrationKeyInfo: "Pobierz generyczny klucz integracyjny API dla usługi, którego wartość skopiowanego tokena URL jest zwykle w formacie \"aaaaaaaa-bbb-cccc-dddd-eeeeee\".",
|
||||||
|
goAlert: "GoAlert",
|
||||||
|
backupOutdatedWarning: "Przestarzałe: ponieważ dodano wiele funkcji i funkcja tworzenia kopii zapasowych nie jest wystarczająco utrzymywana, nie może generować ani przywracać pełnej kopii zapasowej.",
|
||||||
|
backupRecommend: "Zamiast tego należy wykonać bezpośrednią kopię zapasową woluminu lub folderu danych (./data/).",
|
||||||
|
Optional: "Opcjonalne",
|
||||||
|
squadcast: "Squadcast",
|
||||||
|
SendKey: "SendKey",
|
||||||
|
"SMSManager API Docs": "Dokumentacja API SMSManager ",
|
||||||
|
"Gateway Type": "Typ bramy",
|
||||||
|
SMSManager: "SMSManager",
|
||||||
|
"You can divide numbers with": "Możesz dzielić liczby przez",
|
||||||
|
or: "lub",
|
||||||
|
recurringInterval: "odstęp czasu",
|
||||||
|
Recurring: "powtarzający się",
|
||||||
|
strategyManual: "Aktywowany/dezaktywowany ręcznie",
|
||||||
|
warningTimezone: "Używa strefy czasowej serwera",
|
||||||
|
weekdayShortMon: "pon",
|
||||||
|
weekdayShortTue: "wt",
|
||||||
|
weekdayShortWed: "śr",
|
||||||
|
weekdayShortThu: "czw",
|
||||||
|
weekdayShortFri: "pt",
|
||||||
|
weekdayShortSat: "sob",
|
||||||
|
weekdayShortSun: "niedz",
|
||||||
|
dayOfWeek: "Dzień tygodnia",
|
||||||
|
dayOfMonth: "Dzień miesiąca",
|
||||||
|
lastDay: "Ostatni dzień",
|
||||||
|
lastDay1: "Ostatni dzień miesiąca",
|
||||||
|
lastDay2: "2. ostatni dzień miesiąca",
|
||||||
|
lastDay3: "3. ostatni dzień miesiąca",
|
||||||
|
lastDay4: "4. ostatni dzień miesiąca",
|
||||||
|
"No Maintenance": "Brak konserwacji",
|
||||||
|
pauseMaintenanceMsg: "Jesteś pewien, że chcesz zatrzymać?",
|
||||||
|
"maintenanceStatus-under-maintenance": "Podczas konserwacji",
|
||||||
|
"maintenanceStatus-inactive": "Nieaktywny",
|
||||||
|
"maintenanceStatus-scheduled": "Zaplanowany",
|
||||||
|
"maintenanceStatus-ended": "Zakończony",
|
||||||
|
"maintenanceStatus-unknown": "Nieznany",
|
||||||
|
"Display Timezone": "Wyświetlana strefa czasowa",
|
||||||
|
"Server Timezone": "Strefa czasowa serwera",
|
||||||
|
statusPageMaintenanceEndDate: "Koniec",
|
||||||
};
|
};
|
||||||
|
@@ -2,7 +2,7 @@ export default {
|
|||||||
languageName: "简体中文",
|
languageName: "简体中文",
|
||||||
checkEverySecond: "检测频率 {0} 秒",
|
checkEverySecond: "检测频率 {0} 秒",
|
||||||
retryCheckEverySecond: "重试间隔 {0} 秒",
|
retryCheckEverySecond: "重试间隔 {0} 秒",
|
||||||
retriesDescription: "服务被标记为故障并发送通知之前得最大重试次数",
|
retriesDescription: "服务被标记为故障并发送通知之前的最大重试次数",
|
||||||
ignoreTLSError: "忽略 HTTPS 站点的 TLS/SSL 错误",
|
ignoreTLSError: "忽略 HTTPS 站点的 TLS/SSL 错误",
|
||||||
upsideDownModeDescription: "反转状态监控,如果服务可访问,则认为是故障。",
|
upsideDownModeDescription: "反转状态监控,如果服务可访问,则认为是故障。",
|
||||||
maxRedirectDescription: "允许的最大重定向次数。设置为 0 禁用重定向。",
|
maxRedirectDescription: "允许的最大重定向次数。设置为 0 禁用重定向。",
|
||||||
|
@@ -9,11 +9,24 @@ export default {
|
|||||||
upsideDownModeDescription: "反轉顯示狀態。若服務可以連線,將顯示離線。",
|
upsideDownModeDescription: "反轉顯示狀態。若服務可以連線,將顯示離線。",
|
||||||
maxRedirectDescription: "最大重新導向跟隨次數。設為 0 將停用重新導向。",
|
maxRedirectDescription: "最大重新導向跟隨次數。設為 0 將停用重新導向。",
|
||||||
acceptedStatusCodesDescription: "選擇視為成功回應的狀態碼。",
|
acceptedStatusCodesDescription: "選擇視為成功回應的狀態碼。",
|
||||||
|
Maintenance: "維護",
|
||||||
|
statusMaintenance: "維護",
|
||||||
|
"Schedule maintenance": "排程維護",
|
||||||
|
"Affected Monitors": "受影響的監測器",
|
||||||
|
"Pick Affected Monitors...": "挑選受影響的監測器...",
|
||||||
|
"Start of maintenance": "維護起始",
|
||||||
|
"All Status Pages": "所有狀態頁",
|
||||||
|
"Select status pages...": "選擇狀態頁...",
|
||||||
|
recurringIntervalMessage: "每日執行 | 每 {0} 天執行",
|
||||||
|
affectedMonitorsDescription: "選擇受目前維護影響的監測器",
|
||||||
|
affectedStatusPages: "在已選取的狀態頁中顯示此維護訊息",
|
||||||
|
atLeastOneMonitor: "至少選擇一個受影響的監測器",
|
||||||
passwordNotMatchMsg: "密碼不相符。",
|
passwordNotMatchMsg: "密碼不相符。",
|
||||||
notificationDescription: "必須將通知指派給監測器才能運作。",
|
notificationDescription: "必須將通知指派給監測器才能運作。",
|
||||||
keywordDescription: "HTML 或 JSON 回應的搜尋關鍵字。區分大小寫。",
|
keywordDescription: "HTML 或 JSON 回應的搜尋關鍵字。區分大小寫。",
|
||||||
pauseDashboardHome: "暫停",
|
pauseDashboardHome: "暫停",
|
||||||
deleteMonitorMsg: "您確定要刪除此監測器嗎?",
|
deleteMonitorMsg: "您確定要刪除此監測器嗎?",
|
||||||
|
deleteMaintenanceMsg: "您確定要刪除此維護嗎?",
|
||||||
deleteNotificationMsg: "您確定要為所有監測器刪除此通知嗎?",
|
deleteNotificationMsg: "您確定要為所有監測器刪除此通知嗎?",
|
||||||
dnsPortDescription: "DNS 伺服器連接埠。預設為 53。您可以隨時變更連接埠。",
|
dnsPortDescription: "DNS 伺服器連接埠。預設為 53。您可以隨時變更連接埠。",
|
||||||
resolverserverDescription: "Cloudflare 為預設伺服器。您可以隨時更換解析伺服器。",
|
resolverserverDescription: "Cloudflare 為預設伺服器。您可以隨時更換解析伺服器。",
|
||||||
@@ -305,7 +318,7 @@ export default {
|
|||||||
Method: "方法",
|
Method: "方法",
|
||||||
Body: "主體",
|
Body: "主體",
|
||||||
Headers: "標頭",
|
Headers: "標頭",
|
||||||
PushUrl: "Push URL",
|
PushUrl: "Push 網址",
|
||||||
HeadersInvalidFormat: "要求標頭不是有效的 JSON:",
|
HeadersInvalidFormat: "要求標頭不是有效的 JSON:",
|
||||||
BodyInvalidFormat: "請求主體不是有效的 JSON:",
|
BodyInvalidFormat: "請求主體不是有效的 JSON:",
|
||||||
"Monitor History": "監測器歷史紀錄",
|
"Monitor History": "監測器歷史紀錄",
|
||||||
@@ -582,4 +595,40 @@ export default {
|
|||||||
goAlert: "GoAlert",
|
goAlert: "GoAlert",
|
||||||
backupOutdatedWarning: "過時:由於新功能的增加,且未妥善維護,故此備份功能無法產生或復原完整備份。",
|
backupOutdatedWarning: "過時:由於新功能的增加,且未妥善維護,故此備份功能無法產生或復原完整備份。",
|
||||||
backupRecommend: "請直接備份磁碟區或 ./data/ 資料夾。",
|
backupRecommend: "請直接備份磁碟區或 ./data/ 資料夾。",
|
||||||
|
"Optional": "選填",
|
||||||
|
squadcast: "Squadcast",
|
||||||
|
SendKey: "SendKey",
|
||||||
|
"SMSManager API Docs": "SMSManager API 文件 ",
|
||||||
|
"Gateway Type": "閘道類型",
|
||||||
|
SMSManager: "SMSManager",
|
||||||
|
"You can divide numbers with": "若要除數,您可以使用",
|
||||||
|
"or": "或是",
|
||||||
|
recurringInterval: "間隔",
|
||||||
|
"Recurring": "週期性",
|
||||||
|
strategyManual: "手動切換使用中/非使用中",
|
||||||
|
warningTimezone: "正在使用伺服器的時區",
|
||||||
|
weekdayShortMon: "一",
|
||||||
|
weekdayShortTue: "二",
|
||||||
|
weekdayShortWed: "三",
|
||||||
|
weekdayShortThu: "四",
|
||||||
|
weekdayShortFri: "五",
|
||||||
|
weekdayShortSat: "六",
|
||||||
|
weekdayShortSun: "日",
|
||||||
|
dayOfWeek: "每周特定一天",
|
||||||
|
dayOfMonth: "每月特定一天",
|
||||||
|
lastDay: "最後一天",
|
||||||
|
lastDay1: "每月的最後一天",
|
||||||
|
lastDay2: "每月的倒數第二天",
|
||||||
|
lastDay3: "每月的倒數第三天",
|
||||||
|
lastDay4: "每月的倒數第四天",
|
||||||
|
"No Maintenance": "無維護",
|
||||||
|
pauseMaintenanceMsg: "您確定要暫停嗎?",
|
||||||
|
"maintenanceStatus-under-maintenance": "維護中",
|
||||||
|
"maintenanceStatus-inactive": "非使用中",
|
||||||
|
"maintenanceStatus-scheduled": "已排程",
|
||||||
|
"maintenanceStatus-ended": "已結束",
|
||||||
|
"maintenanceStatus-unknown": "未知",
|
||||||
|
"Display Timezone": "顯示時區",
|
||||||
|
"Server Timezone": "伺服器時區",
|
||||||
|
statusPageMaintenanceEndDate: "結束",
|
||||||
};
|
};
|
||||||
|
@@ -58,7 +58,6 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
window.addEventListener("resize", this.onResize);
|
|
||||||
this.initSocketIO();
|
this.initSocketIO();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -89,7 +89,7 @@
|
|||||||
<label for="strategy" class="form-label">{{ $t("Strategy") }}</label>
|
<label for="strategy" class="form-label">{{ $t("Strategy") }}</label>
|
||||||
<select id="strategy" v-model="maintenance.strategy" class="form-select">
|
<select id="strategy" v-model="maintenance.strategy" class="form-select">
|
||||||
<option value="manual">{{ $t("strategyManual") }}</option>
|
<option value="manual">{{ $t("strategyManual") }}</option>
|
||||||
<option value="single">Single Maintenance Window</option>
|
<option value="single">{{ $t("Single Maintenance Window") }}</option>
|
||||||
<option value="recurring-interval">{{ $t("Recurring") }} - {{ $t("recurringInterval") }}</option>
|
<option value="recurring-interval">{{ $t("Recurring") }} - {{ $t("recurringInterval") }}</option>
|
||||||
<option value="recurring-weekday">{{ $t("Recurring") }} - {{ $t("dayOfWeek") }}</option>
|
<option value="recurring-weekday">{{ $t("Recurring") }} - {{ $t("dayOfWeek") }}</option>
|
||||||
<option value="recurring-day-of-month">{{ $t("Recurring") }} - {{ $t("dayOfMonth") }}</option>
|
<option value="recurring-day-of-month">{{ $t("Recurring") }} - {{ $t("dayOfMonth") }}</option>
|
||||||
@@ -284,7 +284,7 @@ export default {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "weekday4",
|
id: "weekday4",
|
||||||
langKey: "weekdayShortTue",
|
langKey: "weekdayShortThu",
|
||||||
value: 4,
|
value: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -24,6 +24,9 @@
|
|||||||
<option value="keyword">
|
<option value="keyword">
|
||||||
HTTP(s) - {{ $t("Keyword") }}
|
HTTP(s) - {{ $t("Keyword") }}
|
||||||
</option>
|
</option>
|
||||||
|
<option value="grpc-keyword">
|
||||||
|
gRPC(s) - {{ $t("Keyword") }}
|
||||||
|
</option>
|
||||||
<option value="dns">
|
<option value="dns">
|
||||||
DNS
|
DNS
|
||||||
</option>
|
</option>
|
||||||
@@ -46,11 +49,14 @@
|
|||||||
MQTT
|
MQTT
|
||||||
</option>
|
</option>
|
||||||
<option value="sqlserver">
|
<option value="sqlserver">
|
||||||
SQL Server
|
Microsoft SQL Server
|
||||||
</option>
|
</option>
|
||||||
<option value="postgres">
|
<option value="postgres">
|
||||||
PostgreSQL
|
PostgreSQL
|
||||||
</option>
|
</option>
|
||||||
|
<option value="mysql">
|
||||||
|
MySQL/MariaDB
|
||||||
|
</option>
|
||||||
<option value="radius">
|
<option value="radius">
|
||||||
Radius
|
Radius
|
||||||
</option>
|
</option>
|
||||||
@@ -70,6 +76,12 @@
|
|||||||
<input id="url" v-model="monitor.url" type="url" class="form-control" pattern="https?://.+" required>
|
<input id="url" v-model="monitor.url" type="url" class="form-control" pattern="https?://.+" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- gRPC URL -->
|
||||||
|
<div v-if="monitor.type === 'grpc-keyword' " class="my-3">
|
||||||
|
<label for="grpc-url" class="form-label">{{ $t("URL") }}</label>
|
||||||
|
<input id="grpc-url" v-model="monitor.grpcUrl" type="url" class="form-control" pattern="[^\:]+:[0-9]{5}" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Push URL -->
|
<!-- Push URL -->
|
||||||
<div v-if="monitor.type === 'push' " class="my-3">
|
<div v-if="monitor.type === 'push' " class="my-3">
|
||||||
<label for="push-url" class="form-label">{{ $t("PushUrl") }}</label>
|
<label for="push-url" class="form-label">{{ $t("PushUrl") }}</label>
|
||||||
@@ -81,7 +93,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Keyword -->
|
<!-- Keyword -->
|
||||||
<div v-if="monitor.type === 'keyword' " class="my-3">
|
<div v-if="monitor.type === 'keyword' || monitor.type === 'grpc-keyword' " class="my-3">
|
||||||
<label for="keyword" class="form-label">{{ $t("Keyword") }}</label>
|
<label for="keyword" class="form-label">{{ $t("Keyword") }}</label>
|
||||||
<input id="keyword" v-model="monitor.keyword" type="text" class="form-control" required>
|
<input id="keyword" v-model="monitor.keyword" type="text" class="form-control" required>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
@@ -235,8 +247,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- SQL Server and PostgreSQL -->
|
<!-- SQL Server / PostgreSQL / MySQL -->
|
||||||
<template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres'">
|
<template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres' || monitor.type === 'mysql'">
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
<label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label>
|
||||||
|
|
||||||
@@ -246,6 +258,9 @@
|
|||||||
<template v-if="monitor.type === 'postgres'">
|
<template v-if="monitor.type === 'postgres'">
|
||||||
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="postgres://username:password@host:port/database">
|
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="postgres://username:password@host:port/database">
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="monitor.type === 'mysql'">
|
||||||
|
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="mysql://username:password@host:port/database">
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<label for="sqlQuery" class="form-label">{{ $t("Query") }}</label>
|
<label for="sqlQuery" class="form-label">{{ $t("Query") }}</label>
|
||||||
@@ -313,7 +328,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- HTTP / Keyword only -->
|
<!-- HTTP / Keyword only -->
|
||||||
<template v-if="monitor.type === 'http' || monitor.type === 'keyword' ">
|
<template v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'grpc-keyword' ">
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<label for="maxRedirects" class="form-label">{{ $t("Max. Redirects") }}</label>
|
<label for="maxRedirects" class="form-label">{{ $t("Max. Redirects") }}</label>
|
||||||
<input id="maxRedirects" v-model="monitor.maxredirects" type="number" class="form-control" required min="0" step="1">
|
<input id="maxRedirects" v-model="monitor.maxredirects" type="number" class="form-control" required min="0" step="1">
|
||||||
@@ -491,6 +506,55 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- gRPC Options -->
|
||||||
|
<template v-if="monitor.type === 'grpc-keyword' ">
|
||||||
|
<!-- Proto service enable TLS -->
|
||||||
|
<h2 class="mt-5 mb-2">{{ $t("GRPC Options") }}</h2>
|
||||||
|
<div class="my-3 form-check">
|
||||||
|
<input id="grpc-enable-tls" v-model="monitor.grpcEnableTls" class="form-check-input" type="checkbox" value="">
|
||||||
|
<label class="form-check-label" for="grpc-enable-tls">
|
||||||
|
{{ $t("Enable TLS") }}
|
||||||
|
</label>
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("enableGRPCTls") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Proto service name data -->
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="protobuf" class="form-label">{{ $t("Proto Service Name") }}</label>
|
||||||
|
<input id="name" v-model="monitor.grpcServiceName" type="text" class="form-control" :placeholder="protoServicePlaceholder" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Proto method data -->
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="protobuf" class="form-label">{{ $t("Proto Method") }}</label>
|
||||||
|
<input id="name" v-model="monitor.grpcMethod" type="text" class="form-control" :placeholder="protoMethodPlaceholder" required>
|
||||||
|
<div class="form-text">
|
||||||
|
{{ $t("grpcMethodDescription") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Proto data -->
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="protobuf" class="form-label">{{ $t("Proto Content") }}</label>
|
||||||
|
<textarea id="protobuf" v-model="monitor.grpcProtobuf" class="form-control" :placeholder="protoBufDataPlaceholder"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Body -->
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="body" class="form-label">{{ $t("Body") }}</label>
|
||||||
|
<textarea id="body" v-model="monitor.grpcBody" class="form-control" :placeholder="bodyPlaceholder"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Metadata: temporary disable waiting for next PR allow to send gRPC with metadata -->
|
||||||
|
<template v-if="false">
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="metadata" class="form-label">{{ $t("Metadata") }}</label>
|
||||||
|
<textarea id="metadata" v-model="monitor.grpcMetadata" class="form-control" :placeholder="headersPlaceholder"></textarea>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -569,6 +633,40 @@ export default {
|
|||||||
return this.$root.baseURL + "/api/push/" + this.monitor.pushToken + "?status=up&msg=OK&ping=";
|
return this.$root.baseURL + "/api/push/" + this.monitor.pushToken + "?status=up&msg=OK&ping=";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
protoServicePlaceholder() {
|
||||||
|
return this.$t("Example:", [ "Health" ]);
|
||||||
|
},
|
||||||
|
|
||||||
|
protoMethodPlaceholder() {
|
||||||
|
return this.$t("Example:", [ "check" ]);
|
||||||
|
},
|
||||||
|
|
||||||
|
protoBufDataPlaceholder() {
|
||||||
|
return this.$t("Example:", [ `
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package grpc.health.v1;
|
||||||
|
|
||||||
|
service Health {
|
||||||
|
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
|
||||||
|
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message HealthCheckRequest {
|
||||||
|
string service = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HealthCheckResponse {
|
||||||
|
enum ServingStatus {
|
||||||
|
UNKNOWN = 0;
|
||||||
|
SERVING = 1;
|
||||||
|
NOT_SERVING = 2;
|
||||||
|
SERVICE_UNKNOWN = 3; // Used only by the Watch method.
|
||||||
|
}
|
||||||
|
ServingStatus status = 1;
|
||||||
|
}
|
||||||
|
` ]);
|
||||||
|
},
|
||||||
bodyPlaceholder() {
|
bodyPlaceholder() {
|
||||||
return this.$t("Example:", [ `
|
return this.$t("Example:", [ `
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user