mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-11 16:54:35 -05:00
Merge branch 'master' into master
This commit is contained in:
commit
f24002838c
@ -77,6 +77,8 @@ module.exports = {
|
||||
"no-empty": ["error", {
|
||||
"allowEmptyCatch": true
|
||||
}],
|
||||
"no-control-regex": "off"
|
||||
"no-control-regex": "off",
|
||||
"one-var": ["error", "never"],
|
||||
"max-statements-per-line": ["error", { "max": 1 }]
|
||||
},
|
||||
}
|
||||
|
@ -73,6 +73,12 @@ For example, recently, because I am not a python expert, I spent a 2 hours to re
|
||||
npm install --dev
|
||||
```
|
||||
|
||||
For npm@7, you need --legacy-peer-deps
|
||||
|
||||
```
|
||||
npm install --legacy-peer-deps --dev
|
||||
```
|
||||
|
||||
# Backend Dev
|
||||
|
||||
```bash
|
||||
|
27
README.md
27
README.md
@ -19,14 +19,6 @@ It is a self-hosted monitoring tool like "Uptime Robot".
|
||||
|
||||
## 🔧 How to Install
|
||||
|
||||
### 🚀 Installer via CLI
|
||||
|
||||
Interactive CLI installer, supports Docker or without Docker.
|
||||
|
||||
```bash
|
||||
curl -o kuma_install.sh http://git.kuma.pet/install.sh && sudo bash kuma_install.sh
|
||||
```
|
||||
|
||||
### 🐳 Docker
|
||||
|
||||
```bash
|
||||
@ -36,6 +28,25 @@ docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name upti
|
||||
|
||||
Browse to http://localhost:3001 after started.
|
||||
|
||||
### 💪🏻 Without Docker
|
||||
|
||||
Required Tools: Node.js >= 14, git and pm2.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/louislam/uptime-kuma.git
|
||||
cd uptime-kuma
|
||||
npm run setup
|
||||
|
||||
# Option 1. Try it
|
||||
node server/server.js
|
||||
|
||||
# (Recommended) Option 2. Run in background using PM2
|
||||
# Install PM2 if you don't have: npm install pm2 -g
|
||||
pm2 start server/server.js --name uptime-kuma
|
||||
```
|
||||
|
||||
Browse to http://localhost:3001 after started.
|
||||
|
||||
### Advanced Installation
|
||||
|
||||
If you need more options or need to browse via a reserve proxy, please read:
|
||||
|
10
dockerfile
10
dockerfile
@ -2,22 +2,20 @@
|
||||
FROM node:14-alpine3.12 AS release
|
||||
WORKDIR /app
|
||||
|
||||
# split the sqlite install here, so that it can caches the prebuilt
|
||||
RUN apk add --no-cache --virtual .build-deps make g++ python3 python3-dev && \
|
||||
# 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 better-sqlite3@7.4.3 bcrypt@5.0.1 && \
|
||||
npm install mapbox/node-sqlite3#593c9d && \
|
||||
apk del .build-deps && \
|
||||
rm -f /usr/bin/python
|
||||
|
||||
# Touching above code may causes sqlite3 re-compile again, painful slow.
|
||||
|
||||
# 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 && npm run build && npm prune
|
||||
RUN npm install --legacy-peer-deps && npm run build && npm prune
|
||||
|
||||
EXPOSE 3001
|
||||
VOLUME ["/app/data"]
|
||||
|
@ -212,8 +212,8 @@ if (type == "local") {
|
||||
bash("check=$(docker info)");
|
||||
|
||||
bash("if [[ \"$check\" == *\"Is the docker daemon running\"* ]]; then
|
||||
echo \"Error: docker is not running\"
|
||||
exit 1
|
||||
\"echo\" \"Error: docker is not running\"
|
||||
\"exit\" \"1\"
|
||||
fi");
|
||||
|
||||
if ("$3" != "") {
|
||||
|
3
extra/update-language-files/.gitignore
vendored
Normal file
3
extra/update-language-files/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package-lock.json
|
||||
test.js
|
||||
languages/
|
77
extra/update-language-files/index.js
Normal file
77
extra/update-language-files/index.js
Normal file
@ -0,0 +1,77 @@
|
||||
// Need to use es6 to read language files
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import util from "util";
|
||||
|
||||
// https://stackoverflow.com/questions/13786160/copy-folder-recursively-in-node-js
|
||||
/**
|
||||
* Look ma, it's cp -R.
|
||||
* @param {string} src The path to the thing to copy.
|
||||
* @param {string} dest The path to the new copy.
|
||||
*/
|
||||
const copyRecursiveSync = function (src, dest) {
|
||||
let exists = fs.existsSync(src);
|
||||
let stats = exists && fs.statSync(src);
|
||||
let isDirectory = exists && stats.isDirectory();
|
||||
if (isDirectory) {
|
||||
fs.mkdirSync(dest);
|
||||
fs.readdirSync(src).forEach(function (childItemName) {
|
||||
copyRecursiveSync(path.join(src, childItemName),
|
||||
path.join(dest, childItemName));
|
||||
});
|
||||
} else {
|
||||
fs.copyFileSync(src, dest);
|
||||
}
|
||||
};
|
||||
console.log(process.argv)
|
||||
const baseLangCode = process.argv[2] || "zh-HK";
|
||||
console.log("Base Lang: " + baseLangCode);
|
||||
fs.rmdirSync("./languages", { recursive: true });
|
||||
copyRecursiveSync("../../src/languages", "./languages");
|
||||
|
||||
const en = (await import("./languages/en.js")).default;
|
||||
const baseLang = (await import(`./languages/${baseLangCode}.js`)).default;
|
||||
const files = fs.readdirSync("./languages");
|
||||
console.log(files);
|
||||
for (const file of files) {
|
||||
if (file.endsWith(".js")) {
|
||||
console.log("Processing " + file);
|
||||
const lang = await import("./languages/" + file);
|
||||
|
||||
let obj;
|
||||
|
||||
if (lang.default) {
|
||||
console.log("is js module");
|
||||
obj = lang.default;
|
||||
} else {
|
||||
console.log("empty file");
|
||||
obj = {
|
||||
languageName: "<Your Language name in your language (not in English)>"
|
||||
};
|
||||
}
|
||||
|
||||
// En first
|
||||
for (const key in en) {
|
||||
if (! obj[key]) {
|
||||
obj[key] = en[key];
|
||||
}
|
||||
}
|
||||
|
||||
// Base second
|
||||
for (const key in baseLang) {
|
||||
if (! obj[key]) {
|
||||
obj[key] = key;
|
||||
}
|
||||
}
|
||||
|
||||
const code = "export default " + util.inspect(obj, {
|
||||
depth: null,
|
||||
});
|
||||
|
||||
fs.writeFileSync(`../../src/languages/${file}`, code);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fs.rmdirSync("./languages", { recursive: true });
|
12
extra/update-language-files/package.json
Normal file
12
extra/update-language-files/package.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "update-language-files",
|
||||
"type": "module",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
}
|
@ -176,8 +176,8 @@ else
|
||||
fi
|
||||
check=$(docker info)
|
||||
if [[ "$check" == *"Is the docker daemon running"* ]]; then
|
||||
echo "Error: docker is not running"
|
||||
exit 1
|
||||
"echo" "Error: docker is not running"
|
||||
"exit" "1"
|
||||
fi
|
||||
if [ "$3" != "" ]; then
|
||||
port="$3"
|
||||
|
4650
package-lock.json
generated
4650
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uptime-kuma",
|
||||
"version": "1.3.2",
|
||||
"version": "1.5.2",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -20,10 +20,11 @@
|
||||
"update": "",
|
||||
"build": "vite build",
|
||||
"vite-preview-dist": "vite preview --host",
|
||||
"build-docker": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.3.2 --target release . --push",
|
||||
"build-docker": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.5.2 --target release . --push",
|
||||
"build-docker-nightly": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push",
|
||||
"build-docker-nightly-amd64": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
|
||||
"setup": "git checkout 1.3.2 && npm install && npm run build",
|
||||
"build-docker-1.5.0-debian": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:1.5.0-debian --target release . --push",
|
||||
"setup": "git checkout 1.5.2 && npm install --legacy-peer-deps && node node_modules/esbuild/install.js && npm run build && npm prune",
|
||||
"update-version": "node extra/update-version.js",
|
||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||
"reset-password": "node extra/reset-password.js",
|
||||
@ -32,8 +33,8 @@
|
||||
"test-install-script-alpine3": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/alpine3.dockerfile .",
|
||||
"test-install-script-ubuntu": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/ubuntu.dockerfile .",
|
||||
"test-install-script-ubuntu1604": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/ubuntu1604.dockerfile .",
|
||||
"test-install-script-debian": "npm run compile-install-script && docker build --progress plain -f test/test_install_script/debian.dockerfile .",
|
||||
"simple-dns-server": "node extra/simple-dns-server.js"
|
||||
"simple-dns-server": "node extra/simple-dns-server.js",
|
||||
"update-language-files": "cd extra/update-language-files && node index.js %npm_config_base_lang% && eslint ../../src/languages/**.js --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
@ -43,10 +44,9 @@
|
||||
"@popperjs/core": "^2.9.3",
|
||||
"args-parser": "^1.3.0",
|
||||
"axios": "^0.21.1",
|
||||
"bcrypt": "^5.0.1",
|
||||
"better-sqlite3": "^7.4.3",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bootstrap": "^5.1.0",
|
||||
"chart.js": "^3.5.0",
|
||||
"chart.js": "^3.5.1",
|
||||
"chartjs-adapter-dayjs": "^1.0.0",
|
||||
"command-exists": "^1.2.9",
|
||||
"compare-versions": "^3.6.0",
|
||||
@ -60,9 +60,10 @@
|
||||
"password-hash": "^1.2.2",
|
||||
"prom-client": "^13.2.0",
|
||||
"prometheus-api-metrics": "^3.2.0",
|
||||
"redbean-node": "0.1.1",
|
||||
"redbean-node": "0.1.2",
|
||||
"socket.io": "^4.1.3",
|
||||
"socket.io-client": "^4.1.3",
|
||||
"sqlite3": "github:mapbox/node-sqlite3#593c9d",
|
||||
"tcp-ping": "^0.1.1",
|
||||
"v-pagination-3": "^0.1.6",
|
||||
"vue": "^3.2.2",
|
||||
|
@ -13,9 +13,6 @@ class Database {
|
||||
static async connect() {
|
||||
const acquireConnectionTimeout = 120 * 1000;
|
||||
|
||||
R.useBetterSQLite3 = true;
|
||||
R.betterSQLite3Options.timeout = acquireConnectionTimeout;
|
||||
|
||||
R.setup("sqlite", {
|
||||
filename: Database.path,
|
||||
useNullAsDefault: true,
|
||||
@ -124,11 +121,8 @@ class Database {
|
||||
return statement !== "";
|
||||
})
|
||||
|
||||
// Use better-sqlite3 to run, prevent "This statement does not return data. Use run() instead"
|
||||
const db = await this.getBetterSQLite3Database();
|
||||
|
||||
for (let statement of statements) {
|
||||
db.prepare(statement).run();
|
||||
await R.exec(statement);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ dayjs.extend(timezone)
|
||||
const axios = require("axios");
|
||||
const { Prometheus } = require("../prometheus");
|
||||
const { debug, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
|
||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode } = require("../util-server");
|
||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom } = require("../util-server");
|
||||
const { R } = require("redbean-node");
|
||||
const { BeanModel } = require("redbean-node/dist/bean-model");
|
||||
const { Notification } = require("../notification")
|
||||
@ -353,10 +353,16 @@ class Monitor extends BeanModel {
|
||||
}
|
||||
|
||||
static async sendStats(io, monitorID, userID) {
|
||||
await Monitor.sendAvgPing(24, io, monitorID, userID);
|
||||
await Monitor.sendUptime(24, io, monitorID, userID);
|
||||
await Monitor.sendUptime(24 * 30, io, monitorID, userID);
|
||||
await Monitor.sendCertInfo(io, monitorID, userID);
|
||||
const hasClients = getTotalClientInRoom(io, userID) > 0;
|
||||
|
||||
if (hasClients) {
|
||||
await Monitor.sendAvgPing(24, io, monitorID, userID);
|
||||
await Monitor.sendUptime(24, io, monitorID, userID);
|
||||
await Monitor.sendUptime(24 * 30, io, monitorID, userID);
|
||||
await Monitor.sendCertInfo(io, monitorID, userID);
|
||||
} else {
|
||||
debug("No clients in the room, no need to send stats");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,9 +96,16 @@ class Notification {
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
let url = monitorJSON["url"] === "https://" ? monitorJSON["hostname"] : monitorJSON["url"]
|
||||
if (monitorJSON["port"]) {
|
||||
url += ":" + monitorJSON[port];
|
||||
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.
|
||||
@ -331,7 +338,7 @@ class Notification {
|
||||
await axios.post(notification.mattermostWebhookUrl, mattermostTestData)
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
|
||||
const mattermostChannel = notification.mattermostchannel;
|
||||
const mattermostIconEmoji = notification.mattermosticonemo;
|
||||
const mattermostIconUrl = notification.mattermosticonurl;
|
||||
|
@ -1,5 +1,5 @@
|
||||
const passwordHashOld = require("password-hash");
|
||||
const bcrypt = require("bcrypt");
|
||||
const bcrypt = require("bcryptjs");
|
||||
const saltRounds = 10;
|
||||
|
||||
exports.generate = function (password) {
|
||||
|
@ -1,14 +1,13 @@
|
||||
// https://github.com/ben-bradley/ping-lite/blob/master/ping-lite.js
|
||||
// Fixed on Windows
|
||||
const net = require("net");
|
||||
const spawn = require("child_process").spawn,
|
||||
events = require("events"),
|
||||
fs = require("fs"),
|
||||
WIN = /^win/.test(process.platform),
|
||||
LIN = /^linux/.test(process.platform),
|
||||
MAC = /^darwin/.test(process.platform);
|
||||
FBSD = /^freebsd/.test(process.platform);
|
||||
const { debug } = require("../src/util");
|
||||
const spawn = require("child_process").spawn;
|
||||
const events = require("events");
|
||||
const fs = require("fs");
|
||||
const WIN = /^win/.test(process.platform);
|
||||
const LIN = /^linux/.test(process.platform);
|
||||
const MAC = /^darwin/.test(process.platform);
|
||||
const FBSD = /^freebsd/.test(process.platform);
|
||||
|
||||
module.exports = Ping;
|
||||
|
||||
@ -22,15 +21,17 @@ function Ping(host, options) {
|
||||
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
const timeout = 10;
|
||||
|
||||
if (WIN) {
|
||||
this._bin = "c:/windows/system32/ping.exe";
|
||||
this._args = (options.args) ? options.args : [ "-n", "1", "-w", "5000", host ];
|
||||
this._args = (options.args) ? options.args : [ "-n", "1", "-w", timeout * 1000, host ];
|
||||
this._regmatch = /[><=]([0-9.]+?)ms/;
|
||||
|
||||
} else if (LIN) {
|
||||
this._bin = "/bin/ping";
|
||||
|
||||
const defaultArgs = [ "-n", "-w", "2", "-c", "1", host ];
|
||||
const defaultArgs = [ "-n", "-w", timeout, "-c", "1", host ];
|
||||
|
||||
if (net.isIPv6(host) || options.ipv6) {
|
||||
defaultArgs.unshift("-6");
|
||||
@ -47,13 +48,13 @@ function Ping(host, options) {
|
||||
this._bin = "/sbin/ping";
|
||||
}
|
||||
|
||||
this._args = (options.args) ? options.args : [ "-n", "-t", "2", "-c", "1", host ];
|
||||
this._args = (options.args) ? options.args : [ "-n", "-t", timeout, "-c", "1", host ];
|
||||
this._regmatch = /=([0-9.]+?) ms/;
|
||||
|
||||
|
||||
} else if (FBSD) {
|
||||
this._bin = "/sbin/ping";
|
||||
|
||||
const defaultArgs = [ "-n", "-t", "2", "-c", "1", host ];
|
||||
const defaultArgs = [ "-n", "-t", timeout, "-c", "1", host ];
|
||||
|
||||
if (net.isIPv6(host) || options.ipv6) {
|
||||
defaultArgs.unshift("-6");
|
||||
@ -88,7 +89,9 @@ Ping.prototype.send = function (callback) {
|
||||
return self.emit("result", ms);
|
||||
};
|
||||
|
||||
let _ended, _exited, _errored;
|
||||
let _ended;
|
||||
let _exited;
|
||||
let _errored;
|
||||
|
||||
this._ping = spawn(this._bin, this._args); // spawn the binary
|
||||
|
||||
@ -120,9 +123,9 @@ Ping.prototype.send = function (callback) {
|
||||
});
|
||||
|
||||
function onEnd() {
|
||||
let stdout = this.stdout._stdout,
|
||||
stderr = this.stderr._stderr,
|
||||
ms;
|
||||
let stdout = this.stdout._stdout;
|
||||
let stderr = this.stderr._stderr;
|
||||
let ms;
|
||||
|
||||
if (stderr) {
|
||||
return callback(new Error(stderr));
|
||||
|
@ -248,3 +248,26 @@ exports.checkStatusCode = function (status, accepted_codes) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
exports.getTotalClientInRoom = (io, roomName) => {
|
||||
|
||||
const sockets = io.sockets;
|
||||
|
||||
if (! sockets) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const adapter = sockets.adapter;
|
||||
|
||||
if (! adapter) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const room = adapter.rooms.get(roomName);
|
||||
|
||||
if (room) {
|
||||
return room.size;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ h2 {
|
||||
background-color: #090c10;
|
||||
color: $dark-font-color;
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
&::-webkit-scrollbar-thumb, ::-webkit-scrollbar-thumb {
|
||||
background: $dark-border-color;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="shadow-box list mb-4">
|
||||
<div class="shadow-box list mb-3" :class="{ scrollbar: scrollbar }">
|
||||
<div v-if="Object.keys($root.monitorList).length === 0" class="text-center mt-3">
|
||||
{{ $t("No Monitors, please") }} <router-link to="/add">{{ $t("add one") }}</router-link>
|
||||
</div>
|
||||
@ -34,6 +34,11 @@ export default {
|
||||
Uptime,
|
||||
HeartbeatBar,
|
||||
},
|
||||
props: {
|
||||
scrollbar: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sortedMonitorList() {
|
||||
let result = Object.values(this.$root.monitorList);
|
||||
@ -83,8 +88,13 @@ export default {
|
||||
}
|
||||
|
||||
.list {
|
||||
height: auto;
|
||||
min-height: calc(100vh - 240px);
|
||||
&.scrollbar {
|
||||
min-height: calc(100vh - 240px);
|
||||
max-height: calc(100vh - 30px);
|
||||
overflow-y: auto;
|
||||
position: sticky;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: block;
|
||||
|
10
src/languages/README.md
Normal file
10
src/languages/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# How to translate
|
||||
|
||||
1. Fork this repo.
|
||||
2. Create a language file. (e.g. zh-TW.js) The filename must be ISO language code: http://www.lingoes.net/en/translator/langcode.htm
|
||||
3. `npm run update-language-files --base-lang=de-DE`
|
||||
6. Your language file should be filled in. You can translate now.
|
||||
7. Make a pull request when you have done.
|
||||
|
||||
If you do not have programming skills, let me know in Issue section. I will assist you. 😏
|
||||
|
109
src/languages/da-DK.js
Normal file
109
src/languages/da-DK.js
Normal file
@ -0,0 +1,109 @@
|
||||
export default {
|
||||
languageName: "Danish",
|
||||
Settings: "Indstillinger",
|
||||
Dashboard: "Dashboard",
|
||||
"New Update": "Opdatering tilgængelig",
|
||||
Language: "Sprog",
|
||||
Appearance: "Udseende",
|
||||
Theme: "Tema",
|
||||
General: "Generelt",
|
||||
Version: "Version",
|
||||
"Check Update On GitHub": "Tjek efter opdateringer på Github",
|
||||
List: "Liste",
|
||||
Add: "Tilføj",
|
||||
"Add New Monitor": "Tilføj ny Overvåger",
|
||||
"Quick Stats": "Oversigt",
|
||||
Up: "Aktiv",
|
||||
Down: "Inaktiv",
|
||||
Pending: "Afventer",
|
||||
Unknown: "Ukendt",
|
||||
Pause: "Pause",
|
||||
pauseDashboardHome: "Pauset",
|
||||
Name: "Navn",
|
||||
Status: "Status",
|
||||
DateTime: "Dato / Tid",
|
||||
Message: "Beskeder",
|
||||
"No important events": "Inden vigtige begivenheder",
|
||||
Resume: "Fortsæt",
|
||||
Edit: "Rediger",
|
||||
Delete: "Slet",
|
||||
Current: "Aktuelt",
|
||||
Uptime: "Oppetid",
|
||||
"Cert Exp.": "Certifikatets udløb",
|
||||
days: "Dage",
|
||||
day: "Dag",
|
||||
"-day": "-Dage",
|
||||
hour: "Timer",
|
||||
"-hour": "-Timer",
|
||||
checkEverySecond: "Tjek hvert {0} sekund",
|
||||
"Avg.": "Gennemsnit",
|
||||
Response: " Respons",
|
||||
Ping: "Ping",
|
||||
"Monitor Type": "Overvåger Type",
|
||||
Keyword: "Nøgleord",
|
||||
"Friendly Name": "Visningsnavn",
|
||||
URL: "URL",
|
||||
Hostname: "Hostname",
|
||||
Port: "Port",
|
||||
"Heartbeat Interval": "Taktinterval",
|
||||
Retries: "Gentagelser",
|
||||
retriesDescription: "Maksimalt antal gentagelser, før tjenesten markeres som inaktiv og sender en meddelelse.",
|
||||
Advanced: "Avanceret",
|
||||
ignoreTLSError: "Ignorere TLS/SSL web fejl",
|
||||
"Upside Down Mode": "Omvendt tilstand",
|
||||
upsideDownModeDescription: "Håndter tilstanden omvendt. Hvis tjenesten er tilgængelig, vises den som inaktiv.",
|
||||
"Max. Redirects": "Maks. Omdirigeringer",
|
||||
maxRedirectDescription: "Maksimalt antal omdirigeringer, der skal følges. Indstil til 0 for at deaktivere omdirigeringer.",
|
||||
"Accepted Status Codes": "Tilladte HTTP-Statuskoder",
|
||||
acceptedStatusCodesDescription: "Vælg de statuskoder, der stadig skal vurderes som vellykkede.",
|
||||
Save: "Gem",
|
||||
Notifications: "Underretninger",
|
||||
"Not available, please setup.": "Ikke tilgængelige, opsæt venligst.",
|
||||
"Setup Notification": "Opsæt underretninger",
|
||||
Light: "Lys",
|
||||
Dark: "Mørk",
|
||||
Auto: "Auto",
|
||||
"Theme - Heartbeat Bar": "Tema - Tidslinje",
|
||||
Normal: "Normal",
|
||||
Bottom: "Bunden",
|
||||
None: "Ingen",
|
||||
Timezone: "Tidszone",
|
||||
"Search Engine Visibility": "Søgemaskine synlighed",
|
||||
"Allow indexing": "Tillad indeksering",
|
||||
"Discourage search engines from indexing site": "Frabed søgemaskiner at indeksere webstedet",
|
||||
"Change Password": "Ændre adgangskode",
|
||||
"Current Password": "Nuværende adgangskode",
|
||||
"New Password": "Ny adgangskode",
|
||||
"Repeat New Password": "Gentag den nye adgangskode",
|
||||
passwordNotMatchMsg: "Adgangskoderne er ikke ens.",
|
||||
"Update Password": "Opdater adgangskode",
|
||||
"Disable Auth": "Deaktiver autentificering",
|
||||
"Enable Auth": "Aktiver autentificering",
|
||||
Logout: "Log ud",
|
||||
notificationDescription: "Tildel underretninger til Overvåger(e), så denne funktion træder i kraft.",
|
||||
Leave: "Verlassen",
|
||||
"I understand, please disable": "Jeg er indforstået, deaktiver venligst",
|
||||
Confirm: "Bekræft",
|
||||
Yes: "Ja",
|
||||
No: "Nej",
|
||||
Username: "Brugernavn",
|
||||
Password: "Adgangskode",
|
||||
"Remember me": "Husk mig",
|
||||
Login: "Log ind",
|
||||
"No Monitors, please": "Ingen Overvågere",
|
||||
"add one": "tilføj en",
|
||||
"Notification Type": "Underretningstype",
|
||||
"Email": "E-Mail",
|
||||
"Test": "Test",
|
||||
"Certificate Info": "Certifikatoplysninger",
|
||||
keywordDescription: "Søg efter et søgeord i almindelig HTML- eller JSON -output. Bemærk, at der skelnes mellem store og små bogstaver.",
|
||||
deleteMonitorMsg: "Er du sikker på, at du vil slette overvågeren?",
|
||||
deleteNotificationMsg: "Er du sikker på, at du vil slette denne underretning for alle overvågere? ",
|
||||
resoverserverDescription: "Cloudflare er standardserveren, den kan til enhver tid ændres.",
|
||||
"Resolver Server": "Navne-server",
|
||||
rrtypeDescription: "Vælg den type RR, du vil overvåge.",
|
||||
"Last Result": "Seneste resultat",
|
||||
pauseMonitorMsg: "Er du sikker på, at du vil pause Overvågeren?",
|
||||
"Create your admin account": "Opret din administratorkonto",
|
||||
"Repeat Password": "Gentag adgangskoden",
|
||||
}
|
@ -93,8 +93,8 @@ export default {
|
||||
"No Monitors, please": "Keine Monitore, bitte",
|
||||
"add one": "hinzufügen",
|
||||
"Notification Type": "Benachrichtigungs Dienst",
|
||||
"Email": "E-Mail",
|
||||
"Test": "Test",
|
||||
Email: "E-Mail",
|
||||
Test: "Test",
|
||||
"Certificate Info": "Zertifikatsinfo",
|
||||
keywordDescription: "Suche nach einen Schlüsselwort in einer schlichten HTML oder JSON Ausgabe. Bitte beachte, es wird in der Groß-/Kleinschreibung unterschieden.",
|
||||
deleteMonitorMsg: "Bist du sicher das du den Monitor löschen möchtest?",
|
||||
@ -106,4 +106,5 @@ export default {
|
||||
pauseMonitorMsg: "Bist du sicher das du den Monitor pausieren möchtest?",
|
||||
"Create your admin account": "Erstelle dein Admin Konto",
|
||||
"Repeat Password": "Wiederhole das Passwort",
|
||||
"Resource Record Type": "Resource Record Type"
|
||||
}
|
||||
|
@ -16,4 +16,93 @@ export default {
|
||||
resoverserverDescription: "Cloudflare is the default server, you can change the resolver server anytime.",
|
||||
rrtypeDescription: "Select the RR-Type you want to monitor",
|
||||
pauseMonitorMsg: "Are you sure want to pause?",
|
||||
Settings: "Settings",
|
||||
Dashboard: "Dashboard",
|
||||
"New Update": "New Update",
|
||||
Language: "Language",
|
||||
Appearance: "Appearance",
|
||||
Theme: "Theme",
|
||||
General: "General",
|
||||
Version: "Version",
|
||||
"Check Update On GitHub": "Check Update On GitHub",
|
||||
List: "List",
|
||||
Add: "Add",
|
||||
"Add New Monitor": "Add New Monitor",
|
||||
"Quick Stats": "Quick Stats",
|
||||
Up: "Up",
|
||||
Down: "Down",
|
||||
Pending: "Pending",
|
||||
Unknown: "Unknown",
|
||||
Pause: "Pause",
|
||||
Name: "Name",
|
||||
Status: "Status",
|
||||
DateTime: "DateTime",
|
||||
Message: "Message",
|
||||
"No important events": "No important events",
|
||||
Resume: "Resume",
|
||||
Edit: "Edit",
|
||||
Delete: "Delete",
|
||||
Current: "Current",
|
||||
Uptime: "Uptime",
|
||||
"Cert Exp.": "Cert Exp.",
|
||||
days: "days",
|
||||
day: "day",
|
||||
"-day": "-day",
|
||||
hour: "hour",
|
||||
"-hour": "-hour",
|
||||
Response: "Response",
|
||||
Ping: "Ping",
|
||||
"Monitor Type": "Monitor Type",
|
||||
Keyword: "Keyword",
|
||||
"Friendly Name": "Friendly Name",
|
||||
URL: "URL",
|
||||
Hostname: "Hostname",
|
||||
Port: "Port",
|
||||
"Heartbeat Interval": "Heartbeat Interval",
|
||||
Retries: "Retries",
|
||||
Advanced: "Advanced",
|
||||
"Upside Down Mode": "Upside Down Mode",
|
||||
"Max. Redirects": "Max. Redirects",
|
||||
"Accepted Status Codes": "Accepted Status Codes",
|
||||
Save: "Save",
|
||||
Notifications: "Notifications",
|
||||
"Not available, please setup.": "Not available, please setup.",
|
||||
"Setup Notification": "Setup Notification",
|
||||
Light: "Light",
|
||||
Dark: "Dark",
|
||||
Auto: "Auto",
|
||||
"Theme - Heartbeat Bar": "Theme - Heartbeat Bar",
|
||||
Normal: "Normal",
|
||||
Bottom: "Bottom",
|
||||
None: "None",
|
||||
Timezone: "Timezone",
|
||||
"Search Engine Visibility": "Search Engine Visibility",
|
||||
"Allow indexing": "Allow indexing",
|
||||
"Discourage search engines from indexing site": "Discourage search engines from indexing site",
|
||||
"Change Password": "Change Password",
|
||||
"Current Password": "Current Password",
|
||||
"New Password": "New Password",
|
||||
"Repeat New Password": "Repeat New Password",
|
||||
"Update Password": "Update Password",
|
||||
"Disable Auth": "Disable Auth",
|
||||
"Enable Auth": "Enable Auth",
|
||||
Logout: "Logout",
|
||||
Leave: "Leave",
|
||||
"I understand, please disable": "I understand, please disable",
|
||||
Confirm: "Confirm",
|
||||
Yes: "Yes",
|
||||
No: "No",
|
||||
Username: "Username",
|
||||
Password: "Password",
|
||||
"Remember me": "Remember me",
|
||||
Login: "Login",
|
||||
"No Monitors, please": "No Monitors, please",
|
||||
"add one": "add one",
|
||||
"Notification Type": "Notification Type",
|
||||
Email: "Email",
|
||||
Test: "Test",
|
||||
"Certificate Info": "Certificate Info",
|
||||
"Resolver Server": "Resolver Server",
|
||||
"Resource Record Type": "Resource Record Type",
|
||||
"Last Result": "Last Result"
|
||||
}
|
||||
|
108
src/languages/fr.js
Normal file
108
src/languages/fr.js
Normal file
@ -0,0 +1,108 @@
|
||||
export default {
|
||||
languageName: "Français (France)",
|
||||
Settings: "Paramètres",
|
||||
Dashboard: "Dashboard",
|
||||
"New Update": "Mise à jour disponible",
|
||||
Language: "Langue",
|
||||
Appearance: "Apparence",
|
||||
Theme: "Thème",
|
||||
General: "Général",
|
||||
Version: "Version",
|
||||
"Check Update On GitHub": "Consulter les mises à jour sur Github",
|
||||
List: "Lister",
|
||||
Add: "Ajouter",
|
||||
"Add New Monitor": "Ajouter un nouveau check",
|
||||
"Quick Stats": "Résumé",
|
||||
Up: "En ligne",
|
||||
Down: "Hors ligne",
|
||||
Pending: "Dans la file d'attente",
|
||||
Unknown: "Inconnu",
|
||||
Pause: "En Pause",
|
||||
pauseDashboardHome: "Éléments mis en pause",
|
||||
Name: "Nom",
|
||||
Status: "État",
|
||||
DateTime: "Heure",
|
||||
Message: "Messages",
|
||||
"No important events": "Pas d'évènements important",
|
||||
Resume: "Reprendre",
|
||||
Edit: "Modifier",
|
||||
Delete: "Supprimer",
|
||||
Current: "Actuellement",
|
||||
Uptime: "Uptime",
|
||||
"Cert Exp.": "Cert Exp.",
|
||||
days: "Jours",
|
||||
day: "Jour",
|
||||
"-day": "Demi-Journée",
|
||||
hour: "Heure",
|
||||
"-hour": "Demi-Heure",
|
||||
checkEverySecond: "Vérifier toutes les {0} secondes",
|
||||
"Avg.": "Moy.",
|
||||
Response: "Réponse",
|
||||
Ping: "Ping",
|
||||
"Monitor Type": "Type de Monitoring",
|
||||
Keyword: "Mot-clé",
|
||||
"Friendly Name": "Nom d'affichage",
|
||||
URL: "URL",
|
||||
Hostname: "Nom d'hôte",
|
||||
Port: "Port",
|
||||
"Heartbeat Interval": "Intervale de vérifications",
|
||||
Retries: "Essais",
|
||||
retriesDescription: "Nombre d'essais avant que le service soit déclaré hors-ligne.",
|
||||
Advanced: "Avancé",
|
||||
ignoreTLSError: "Ignorer les erreurs liées au certificat SSL/TLS",
|
||||
"Upside Down Mode": "Mode inversé",
|
||||
upsideDownModeDescription: "Si le service est en ligne il sera alors noté hors-ligne et vice-versa.",
|
||||
"Max. Redirects": "Redirections",
|
||||
maxRedirectDescription: "Nombre maximal de redirections avant que le service soit noté hors-ligne.",
|
||||
"Accepted Status Codes": "Codes HTTP",
|
||||
acceptedStatusCodesDescription: "Si les codes HTTP reçus sont ceux séléctionnés, alors le serveur sera noté en ligne.",
|
||||
Save: "Sauvegarder",
|
||||
Notifications: "Notifications",
|
||||
"Not available, please setup.": "Créez des notifications depuis les paramètres.",
|
||||
"Setup Notification": "Créer une notification",
|
||||
Light: "Clair",
|
||||
Dark: "Sombre",
|
||||
Auto: "Automatique",
|
||||
"Theme - Heartbeat Bar": "Voir les services monitorés",
|
||||
Normal: "Général",
|
||||
Bottom: "Au dessus",
|
||||
None: "Neutre",
|
||||
Timezone: "Fuseau Horaire",
|
||||
"Search Engine Visibility": "SEO",
|
||||
"Allow indexing": "Autoriser l'indexation par des moteurs de recherche",
|
||||
"Discourage search engines from indexing site": "Empêche les moteurs de recherche d'indexer votre site",
|
||||
"Change Password": "Changer le mot de passe",
|
||||
"Current Password": "Mot de passe actuel",
|
||||
"New Password": "Nouveau mot de passe",
|
||||
"Repeat New Password": "Répéter votre nouveau mot de passe",
|
||||
passwordNotMatchMsg: "Les mots de passe ne correspondent pas",
|
||||
"Update Password": "Mettre à jour le mot de passe",
|
||||
"Disable Auth": "Désactiver l'authentification intégrée",
|
||||
"Enable Auth": "Activer l'authentification",
|
||||
Logout: "Se déconnecter",
|
||||
notificationDescription: "Une fois ajoutée, vous devez l'activer manuellement dans les paramètres de vos hosts.",
|
||||
Leave: "Quitter",
|
||||
"I understand, please disable": "Je comprends, je l'ai désactivé",
|
||||
Confirm: "Confirmer",
|
||||
Yes: "Oui",
|
||||
No: "Non",
|
||||
Username: "Nom d'utilisateur",
|
||||
Password: "Mot de passe",
|
||||
"Remember me": "Se souvenir de moi",
|
||||
Login: "Se connecter",
|
||||
"No Monitors, please": "Pas de monitor, veuillez ",
|
||||
"add one": "en ajouter un.",
|
||||
"Notification Type": "Type de notification",
|
||||
Email: "Email",
|
||||
Test: "Tester",
|
||||
keywordDescription: "Le mot clé sera cherché dans la réponse HTML/JSON reçue du site internet.",
|
||||
"Certificate Info": "Des informations sur le certificat SSL",
|
||||
deleteMonitorMsg: "Êtes-vous sûr de vouloir supprimer ce monitor ?",
|
||||
deleteNotificationMsg: "Êtes-vous sûr de vouloir supprimer ce type de notifications ? Une fois désactivée, les services qui l'utilisent ne pourront plus envoyer de notifications.",
|
||||
"Resolver Server": "Serveur DNS utilisé",
|
||||
"Resource Record Type": "Type d'enregistrement DNS recherché",
|
||||
resoverserverDescription: "Le DNS de cloudflare est utilisé par défaut, mais vous pouvez le changer si vous le souhaitez.",
|
||||
rrtypeDescription: "Veuillez séléctionner un type d'enregistrement DNS",
|
||||
pauseMonitorMsg: "Are you sure want to pause?",
|
||||
"Last Result": "Last Result"
|
||||
}
|
@ -93,8 +93,8 @@ export default {
|
||||
"No Monitors, please": "沒有監測器,請",
|
||||
"add one": "新增",
|
||||
"Notification Type": "通知類型",
|
||||
"Email": "電郵",
|
||||
"Test": "測試",
|
||||
Email: "電郵",
|
||||
Test: "測試",
|
||||
keywordDescription: "搜索 HTML 或 JSON 裡是否有出現關鍵字(注意英文大細階)",
|
||||
"Certificate Info": "憑證詳細資料",
|
||||
deleteMonitorMsg: "是否確定刪除這個監測器",
|
||||
@ -103,4 +103,6 @@ export default {
|
||||
"Resource Record Type": "DNS 記錄類型",
|
||||
resoverserverDescription: "預設值為 Cloudflare DNS 伺服器,你可以轉用其他 DNS 伺服器。",
|
||||
rrtypeDescription: "請選擇 DNS 記錄類型",
|
||||
pauseMonitorMsg: "Are you sure want to pause?",
|
||||
"Last Result": "Last Result"
|
||||
}
|
||||
|
@ -40,19 +40,10 @@
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<!-- Add :key to disable vue router re-use the same component -->
|
||||
<router-view v-if="$root.loggedIn" :key="$route.fullPath" />
|
||||
<router-view v-if="$root.loggedIn" />
|
||||
<Login v-if="! $root.loggedIn && $root.allowLoginDialog" />
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="container-fluid">
|
||||
Uptime Kuma -
|
||||
{{ $t("Version") }}: {{ $root.info.version }} -
|
||||
<a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">{{ $t("Check Update On GitHub") }}</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Mobile Only -->
|
||||
<div v-if="$root.isMobile" style="width: 100%; height: 60px;" />
|
||||
<nav v-if="$root.isMobile" class="bottom-nav">
|
||||
@ -190,15 +181,6 @@ main {
|
||||
color: white;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: #aaa;
|
||||
font-size: 13px;
|
||||
margin-top: 10px;
|
||||
padding-bottom: 30px;
|
||||
margin-left: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dark {
|
||||
header {
|
||||
background-color: #161b22;
|
||||
|
@ -26,6 +26,8 @@ import { appName } from "./util.ts";
|
||||
import en from "./languages/en";
|
||||
import zhHK from "./languages/zh-HK";
|
||||
import deDE from "./languages/de-DE";
|
||||
import fr from "./languages/fr";
|
||||
import daDK from "./languages/da-DK";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -92,6 +94,8 @@ const languageList = {
|
||||
en,
|
||||
"zh-HK": zhHK,
|
||||
"de-DE": deDE,
|
||||
"fr": fr,
|
||||
"da-DK": daDK,
|
||||
};
|
||||
|
||||
const i18n = createI18n({
|
||||
|
@ -5,11 +5,12 @@
|
||||
<div>
|
||||
<router-link to="/add" class="btn btn-primary mb-3"><font-awesome-icon icon="plus" /> {{ $t("Add New Monitor") }}</router-link>
|
||||
</div>
|
||||
<MonitorList />
|
||||
<MonitorList scrollbar="true" />
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-7 col-xl-8">
|
||||
<router-view />
|
||||
<div class="col-12 col-md-7 col-xl-8 mb-3">
|
||||
<!-- Add :key to disable vue router re-use the same component -->
|
||||
<router-view :key="$route.fullPath" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -26,7 +27,6 @@ export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
{{ $t("Quick Stats") }}
|
||||
</h1>
|
||||
|
||||
<div class="shadow-box big-padding text-center">
|
||||
<div class="shadow-box big-padding text-center mb-4">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3>{{ $t("Up") }}</h3>
|
||||
@ -170,7 +170,6 @@ export default {
|
||||
|
||||
.shadow-box {
|
||||
padding: 20px;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
table {
|
||||
|
@ -422,4 +422,5 @@ table {
|
||||
color: $dark-font-color;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -155,6 +155,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="container-fluid">
|
||||
Uptime Kuma -
|
||||
{{ $t("Version") }}: {{ $root.info.version }} -
|
||||
<a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">{{ $t("Check Update On GitHub") }}</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<NotificationDialog ref="notificationDialog" />
|
||||
|
||||
<Confirm ref="confirmDisableAuth" btn-style="btn-danger" :yes-text="$t('I understand, please disable')" :no-text="$t('Leave')" @yes="disableAuth">
|
||||
@ -314,4 +322,12 @@ export default {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
color: #aaa;
|
||||
font-size: 13px;
|
||||
margin-top: 20px;
|
||||
padding-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user