diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.md b/.github/ISSUE_TEMPLATE/ask-for-help.md deleted file mode 100644 index 3031e077a..000000000 --- a/.github/ISSUE_TEMPLATE/ask-for-help.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: Ask for help -about: You can ask any question related to Uptime Kuma. -title: '' -labels: help -assignees: '' - ---- -**Is it a duplicated question?** -Please search in Issues without filters: https://github.com/louislam/uptime-kuma/issues?q= - -**Describe your problem** -Please describe what you are asking for - -**Info** -Uptime Kuma Version: -Using Docker?: Yes/No -Docker Version: -Node.js Version (Without Docker only): -OS: -Browser: diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml new file mode 100644 index 000000000..dd1bcaf76 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml @@ -0,0 +1,76 @@ +name: "❓ Ask for help" +description: "Submit any question related to Uptime Kuma" +title: "[Help]: " +labels: [help] +body: + - type: textarea + id: steps-to-reproduce + validations: + required: true + attributes: + label: "📝 Describe your problem" + description: "Please walk us through it step by step." + placeholder: "Describe what are you asking for..." + - type: input + id: uptime-kuma-version + attributes: + label: "🐻 Uptime-Kuma version" + description: "Which version of Uptime-Kuma are you running?" + placeholder: "Ex. 1.9.x" + validations: + required: true + - type: input + id: operating-system + attributes: + label: "💻 Operating System" + description: "Which OS is your server/device running on?" + placeholder: "Ex. Ubuntu 20.04" + validations: + required: true + - type: input + id: browser-vendor + attributes: + label: "🌐 Browser" + description: "Which browser are you running on?" + placeholder: "Ex. Firefox" + validations: + required: true + - type: input + id: docker-version + attributes: + label: "🐋 Docker" + description: "If running with Docker, which version are you running?" + placeholder: "Ex. 20.10.9" + validations: + required: false + - type: input + id: docker-image-tag + attributes: + label: "🏷️ Docker Image Tag" + description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash." + placeholder: "Ex. 1.9.1" + validations: + required: false + - type: input + id: nodejs-version + attributes: + label: "🟩 NodeJS Version" + description: "If running with Node.js? which version are you running?" + placeholder: "14.x" + validations: + required: false + - type: checkboxes + id: no-duplicate-issues + attributes: + label: "👀 Have you spent some time to check if this question has been raised before?" + description: "Please search in the issues without filters [here](https://github.com/louislam/uptime-kuma/issues?q=)" + options: + - label: "I checked and didn't find similar question" + required: true + - type: checkboxes + attributes: + label: "🛡️ Security Policy" + description: Please review the security policy before reporting security related issues/bugs. + options: + - label: I agree to have read this project [Security Policy](https://github.com/louislam/uptime-kuma/security/policy) + required: true diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 069ed6cc0..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: bug -assignees: '' - ---- - -**Is it a duplicated question?** -Please search in Issues without filters: https://github.com/louislam/uptime-kuma/issues?q= - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Info** -Uptime Kuma Version: -Using Docker?: Yes/No -Docker Version: -Node.js Version (Without Docker only): -OS: -Browser: - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Error Log** -It is easier for us to find out the problem. - -Docker: `docker logs <container id>` -PM2: `~/.pm2/logs/` (e.g. `/home/ubuntu/.pm2/logs`) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 000000000..5e3b5bf8a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,100 @@ +name: "🐛 Bug Report" +description: "Submit a bug report to help us improve" +title: "[Bug]: <title>" +labels: [bug] +body: + - type: textarea + id: steps-to-reproduce + validations: + required: true + attributes: + label: "👟 Reproduction steps" + description: "How do you trigger this bug? Please walk us through it step by step." + placeholder: "..." + - type: textarea + id: expected-behavior + validations: + required: true + attributes: + label: "👍 Expected behavior" + description: "What did you think would happen?" + placeholder: "..." + - type: textarea + id: actual-behavior + validations: + required: true + attributes: + label: "👎 Actual Behavior" + description: "What actually happen?" + placeholder: "..." + - type: input + id: uptime-kuma-version + attributes: + label: "🐻 Uptime-Kuma version" + description: "Which version of Uptime-Kuma are you running?" + placeholder: "Ex. 1.9.x" + validations: + required: true + - type: input + id: operating-system + attributes: + label: "💻 Operating System" + description: "Which OS is your server/device running on?" + placeholder: "Ex. Ubuntu 20.04" + validations: + required: true + - type: input + id: browser-vendor + attributes: + label: "🌐 Browser" + description: "Which browser are you running on?" + placeholder: "Ex. Firefox" + validations: + required: true + - type: input + id: docker-version + attributes: + label: "🐋 Docker" + description: "If running with Docker, which version are you running?" + placeholder: "Ex. 20.10.9" + validations: + required: false + - type: input + id: docker-image-tag + attributes: + label: "🏷️ Docker Image Tag" + description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash." + placeholder: "Ex. 1.9.1" + validations: + required: false + - type: input + id: nodejs-version + attributes: + label: "🟩 NodeJS Version" + description: "If running with Node.js? which version are you running?" + placeholder: "14.x" + validations: + required: false + - type: textarea + id: logs + attributes: + label: "📝 Relevant log output" + description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + render: shell + validations: + required: false + - type: checkboxes + id: no-duplicate-issues + attributes: + label: "👀 Have you spent some time to check if this issue has been raised before?" + description: "Please search in the issues without filters [here](https://github.com/louislam/uptime-kuma/issues?q=)" + options: + - label: "I checked and didn't find similar issue" + required: true + - type: checkboxes + attributes: + label: "🛡️ Security Policy" + description: Please review the security policy before reporting security related issues/bugs. + options: + - label: I agree to have read this project [Security Policy](https://github.com/louislam/uptime-kuma/security/policy) + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 4794cc242..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- -**Is it a duplicated question?** -Please search in Issues without filters: https://github.com/louislam/uptime-kuma/issues?q= - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 000000000..bca32552f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,59 @@ +name: 🚀 Feature Request +description: "Submit a proposal for a new feature" +title: "[Feature]: <title>" +labels: [enhancement] +body: + - type: dropdown + id: feature-area + attributes: + label: "🏷️ Feature Request Type" + description: "What kind of feature request is this?" + multiple: true + options: + - API + - New Notification + - New Monitor + - UI Feature + - Other + validations: + required: true + - type: textarea + id: feature-description + validations: + required: true + attributes: + label: "🔖 Feature description" + description: "A clear and concise description of what the feature request is." + placeholder: "You should add ..." + - type: textarea + id: solution + validations: + required: true + attributes: + label: "✔️ Solution" + description: "A clear and concise description of what you want to happen." + placeholder: "In my use-case, ..." + - type: textarea + id: alternatives + validations: + required: false + attributes: + label: "❓ Alternatives" + description: "A clear and concise description of any alternative solutions or features you've considered." + placeholder: "I have considered ..." + - type: textarea + id: additional-context + validations: + required: false + attributes: + label: "📝 Additional Context" + description: "Add any other context or screenshots about the feature request here." + placeholder: "..." + - type: checkboxes + id: no-duplicate-issues + attributes: + label: "👀 Have you spent some time to check if this feature request has been raised before?" + description: "Please search in the issues without filters [here](https://github.com/louislam/uptime-kuma/issues?q=)" + options: + - label: "I checked and didn't find similar feature request" + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..fa0aa883b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +# Description + +Fixes #(issue) + +## Type of change + +Please delete options that are not relevant. + +- Bug fix (non-breaking change which fixes an issue) +- User Interface +- New feature (non-breaking change which adds functionality) +- Breaking change (fix or feature that would cause existing functionality to not work as expected) +- Translation update +- Other +- This change requires a documentation update + +## Checklist + +- [ ] My code follows the style guidelines of this project +- [ ] I ran ESLint and other linters for modified files +- [ ] I have performed a self-review of my own code and test it +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] My changes generate no new warnings +- [ ] My code needed automated testing. I have added them (this is optional task) + +## Screenshots (if any) diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml index c59a61b91..e01c02cee 100644 --- a/.github/workflows/auto-test.yml +++ b/.github/workflows/auto-test.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest, windows-latest] - node-version: [14.x, 16.x] + node-version: [14.x, 16.x, 17.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: diff --git a/.github/workflows/stale-bot b/.github/workflows/stale-bot.yml similarity index 100% rename from .github/workflows/stale-bot rename to .github/workflows/stale-bot.yml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d9b37a3c..c9f186df2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,16 +29,34 @@ The frontend code build into "dist" directory. The server (express.js) exposes t Generally, if the pull request is working fine and it do not affect any existing logic, workflow and perfomance, I will merge into the master branch once it is tested. -If you are not sure, feel free to create an empty pull request draft first. +If you are not sure whether I will accept your pull request, feel free to create an empty pull request draft first. + + +### Recommended Pull Request Guideline + +1. Fork the project +1. Clone your fork repo to local +1. Create a new branch +1. Create an empty commit + `git commit -m "[empty commit] pull request for <YOUR TASK NAME>" --allow-empty` +1. Push to your fork repo +1. Create a pull request: https://github.com/louislam/uptime-kuma/compare +1. Write a proper description +1. Click "Change to draft" ### Pull Request Examples +Here are some example situations in the past. + #### ✅ High - Medium Priority +Easy to review, no breaking change and not touching the existing code + - Add a new notification - Add a chart - Fix a bug - Translations +- Add a independent new feature #### *️⃣ Requires one more reviewer @@ -46,6 +64,17 @@ I do not have such knowledge to test it. - Add k8s supports +#### ⚠ Low Priority - Harsh Mode + +Some pull requests are required to modifiy the core. To be honest, I do not want anyone to try to do that, because it would spend a lot of your time. I will review your pull request harshly. Also you may need to write a lot of unit tests to ensure that there is no breaking change. + +- Touch large parts of code of any very important features +- Touch monitoring logic +- Drop a table or drop a column for any reason +- Touch the entry point of Docker or Node.js +- Modifiy auth + + #### *️⃣ Low Priority It changed my current workflow and require further studies. @@ -54,6 +83,7 @@ It changed my current workflow and require further studies. #### ❌ Won't Merge +- Any breaking changes - Duplicated pull request - Buggy - Existing logic is completely modified or deleted @@ -180,6 +210,13 @@ Patch release = the third digit ([Semantic Versioning](https://semver.org/)) Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages +## Wiki + +Since there is no way to make a pull request to wiki's repo, I have setup another repo to do that. + +https://github.com/louislam/uptime-kuma-wiki + + ## Maintainer Check the latest issues and pull requests: @@ -199,3 +236,19 @@ Checking: - Check all tags is fine on https://hub.docker.com/r/louislam/uptime-kuma/tags - Try the Docker image with tag 1.X.X (Clean install / amd64 / arm64 / armv7) - Try clean install with Node.js + +### Release Wiki + +#### Setup Repo +``` +git clone https://github.com/louislam/uptime-kuma-wiki.git +cd uptime-kuma-wiki +git remote add production https://github.com/louislam/uptime-kuma.wiki.git +``` + +#### Push to Production Wiki +``` +git pull +git push production master +``` + diff --git a/README.md b/README.md index 6caa1a85d..9177cc998 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Uptime Kuma -<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Backers&color=brightgreen" /></a> +<a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/stars/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/pulls/louislam/uptime-kuma" /></a> <a target="_blank" href="https://hub.docker.com/r/louislam/uptime-kuma"><img src="https://img.shields.io/docker/v/louislam/uptime-kuma/latest?label=docker%20image%20ver." /></a> <a target="_blank" href="https://github.com/louislam/uptime-kuma"><img src="https://img.shields.io/github/last-commit/louislam/uptime-kuma" /></a> <a target="_blank" href="https://opencollective.com/uptime-kuma"><img src="https://opencollective.com/uptime-kuma/total/badge.svg?label=Open%20Collective%20Backers&color=brightgreen" /></a> +[![GitHub Sponsors](https://img.shields.io/github/sponsors/louislam?label=GitHub%20Sponsors)](https://github.com/sponsors/louislam) <div align="center" width="100%"> <img src="./public/icon.svg" width="128" alt="" /> @@ -42,7 +43,7 @@ docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name upti Browse to http://localhost:3001 after starting. -### 💪🏻 Without Docker +### 💪🏻 Non-Docker Required Tools: Node.js >= 14, git and pm2. diff --git a/SECURITY.md b/SECURITY.md index a0b2562f4..7b9bfca41 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,8 +9,8 @@ currently being supported with security updates. | Version | Supported | | ------- | ------------------ | -| 1.8.X | :white_check_mark: | -| <= 1.7.X | ❌ | +| 1.9.X | :white_check_mark: | +| <= 1.8.X | ❌ | ### Upgradable Docker Tags diff --git a/extra/download-dist.js b/extra/download-dist.js index 0a08b7f90..dc64166c4 100644 --- a/extra/download-dist.js +++ b/extra/download-dist.js @@ -34,9 +34,11 @@ function download(url) { }); tarStream.on("close", () => { - fs.rmdirSync("./dist-backup", { - recursive: true - }); + if (fs.existsSync("./dist-backup")) { + fs.rmdirSync("./dist-backup", { + recursive: true + }); + } console.log("Done"); }); @@ -44,7 +46,7 @@ function download(url) { if (fs.existsSync("./dist-backup")) { fs.renameSync("./dist-backup", "./dist"); } - console.log("Done"); + console.error("Error from tarStream"); }); response.pipe(tarStream); diff --git a/package-lock.json b/package-lock.json index 551504d75..9f4125291 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "http-graceful-shutdown": "~3.1.4", "iconv-lite": "^0.6.3", "jsonwebtoken": "~8.5.1", + "jwt-decode": "^3.1.2", "limiter": "^2.1.0", "nodemailer": "~6.6.5", "notp": "~2.0.3", @@ -7846,6 +7847,11 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -18495,6 +18501,11 @@ "safe-buffer": "^5.0.1" } }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", diff --git a/package.json b/package.json index 4f3d32ea7..10ad4a08b 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "http-graceful-shutdown": "~3.1.4", "iconv-lite": "^0.6.3", "jsonwebtoken": "~8.5.1", + "jwt-decode": "^3.1.2", "limiter": "^2.1.0", "nodemailer": "~6.6.5", "notp": "~2.0.3", diff --git a/server/database.js b/server/database.js index c9d9cc577..98494251d 100644 --- a/server/database.js +++ b/server/database.js @@ -114,6 +114,7 @@ class Database { // Change to WAL await R.exec("PRAGMA journal_mode = WAL"); await R.exec("PRAGMA cache_size = -12000"); + await R.exec("PRAGMA auto_vacuum = FULL"); console.log("SQLite config:"); console.log(await R.getAll("PRAGMA journal_mode")); @@ -374,6 +375,17 @@ class Database { console.log("Nothing to restore"); } } + + static getSize() { + debug("Database.getSize()"); + let stats = fs.statSync(Database.path); + debug(stats); + return stats.size; + } + + static async shrink() { + await R.exec("VACUUM"); + } } module.exports = Database; diff --git a/server/model/monitor.js b/server/model/monitor.js index fb736291c..2f28e5b95 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -351,6 +351,10 @@ class Monitor extends BeanModel { if (isImportant) { bean.important = true; await Monitor.sendNotification(isFirstBeat, this, bean); + + // Clear Status Page Cache + apicache.clear(); + } else { bean.important = false; } @@ -383,18 +387,32 @@ class Monitor extends BeanModel { } } - this.heartbeatInterval = setTimeout(beat, beatInterval * 1000); + this.heartbeatInterval = setTimeout(safeBeat, beatInterval * 1000); } }; + const safeBeat = async () => { + try { + await beat(); + } catch (e) { + console.trace(e); + console.error("Please report to https://github.com/louislam/uptime-kuma/issues"); + + if (! this.isStop) { + console.log("Try to restart the monitor"); + this.heartbeatInterval = setTimeout(safeBeat, this.interval * 1000); + } + } + }; + // Delay Push Type if (this.type === "push") { setTimeout(() => { - beat(); + safeBeat(); }, this.interval * 1000); } else { - beat(); + safeBeat(); } } @@ -598,9 +616,6 @@ class Monitor extends BeanModel { console.log(e); } } - - // Clear Status Page Cache - apicache.clear(); } } diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js new file mode 100644 index 000000000..4ebe978ad --- /dev/null +++ b/server/notification-providers/bark.js @@ -0,0 +1,89 @@ +// +// bark.js +// UptimeKuma +// +// Created by Lakr Aream on 2021/10/24. +// Copyright © 2021 Lakr Aream. All rights reserved. +// + +const NotificationProvider = require("./notification-provider"); +const { DOWN, UP } = require("../../src/util"); +const { default: axios } = require("axios"); + +// bark is an APN bridge that sends notifications to Apple devices. + +const barkNotificationGroup = "UptimeKuma"; +const barkNotificationAvatar = "https://github.com/louislam/uptime-kuma/raw/master/public/icon.png"; +const barkNotificationSound = "telegraph"; +const successMessage = "Successes!"; + +class Bark extends NotificationProvider { + name = "Bark"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + try { + var barkEndpoint = notification.barkEndpoint; + + // check if the endpoint has a "/" suffix, if so, delete it first + if (barkEndpoint.endsWith("/")) { + barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1); + } + + if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == UP) { + let title = "UptimeKuma Monitor Up"; + return await this.postNotification(title, msg, barkEndpoint); + } + + if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == DOWN) { + let title = "UptimeKuma Monitor Down"; + return await this.postNotification(title, msg, barkEndpoint); + } + + if (msg != null) { + let title = "UptimeKuma Message"; + return await this.postNotification(title, msg, barkEndpoint); + } + + } catch (error) { + throw error; + } + } + + // add additional parameter for better on device styles (iOS 15 optimized) + appendAdditionalParameters(postUrl) { + // grouping all our notifications + postUrl += "?group=" + barkNotificationGroup; + // set icon to uptime kuma icon, 11kb should be fine + postUrl += "&icon=" + barkNotificationAvatar; + // picked a sound, this should follow system's mute status when arrival + postUrl += "&sound=" + barkNotificationSound; + return postUrl; + } + + // thrown if failed to check result, result code should be in range 2xx + checkResult(result) { + if (result.status == null) { + throw new Error("Bark notification failed with invalid response!"); + } + if (result.status < 200 || result.status >= 300) { + throw new Error("Bark notification failed with status code " + result.status); + } + } + + async postNotification(title, subtitle, endpoint) { + // url encode title and subtitle + title = encodeURIComponent(title); + subtitle = encodeURIComponent(subtitle); + let postUrl = endpoint + "/" + title + "/" + subtitle; + postUrl = this.appendAdditionalParameters(postUrl); + let result = await axios.get(postUrl); + this.checkResult(result); + if (result.statusText != null) { + return "Bark notification succeed: " + result.statusText; + } + // because returned in range 200 ..< 300 + return successMessage; + } +} + +module.exports = Bark; diff --git a/server/notification-providers/clicksendsms.js b/server/notification-providers/clicksendsms.js new file mode 100644 index 000000000..74e2f4c59 --- /dev/null +++ b/server/notification-providers/clicksendsms.js @@ -0,0 +1,42 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +class ClickSendSMS extends NotificationProvider { + + name = "clicksendsms"; + + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + let okMsg = "Sent Successfully."; + try { + console.log({ notification }); + let config = { + headers: { + "Content-Type": "application/json", + "Authorization": "Basic " + Buffer.from(notification.clicksendsmsLogin + ":" + notification.clicksendsmsPassword).toString('base64'), + "Accept": "text/json", + } + }; + let data = { + messages: [ + { + "body": msg.replace(/[^\x00-\x7F]/g, ""), + "to": notification.clicksendsmsToNumber, + "source": "uptime-kuma", + "from": notification.clicksendsmsSenderName, + } + ] + }; + let resp = await axios.post("https://rest.clicksend.com/v3/sms/send", data, config); + if (resp.data.data.messages[0].status !== "SUCCESS") { + let error = "Something gone wrong. Api returned " + resp.data.data.messages[0].status + "."; + this.throwGeneralAxiosError(error); + } + + return okMsg; + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = ClickSendSMS; diff --git a/server/notification.js b/server/notification.js index 658216f91..18c823b2b 100644 --- a/server/notification.js +++ b/server/notification.js @@ -8,6 +8,7 @@ const Mattermost = require("./notification-providers/mattermost"); const Matrix = require("./notification-providers/matrix"); const Octopush = require("./notification-providers/octopush"); const PromoSMS = require("./notification-providers/promosms"); +const ClickSendSMS = require("./notification-providers/clicksendsms"); const Pushbullet = require("./notification-providers/pushbullet"); const Pushover = require("./notification-providers/pushover"); const Pushy = require("./notification-providers/pushy"); @@ -21,6 +22,7 @@ const Webhook = require("./notification-providers/webhook"); const Feishu = require("./notification-providers/feishu"); const AliyunSms = require("./notification-providers/aliyun-sms"); const DingDing = require("./notification-providers/dingding"); +const Bark = require("./notification-providers/bark"); class Notification { @@ -45,6 +47,7 @@ class Notification { new Matrix(), new Octopush(), new PromoSMS(), + new ClickSendSMS(), new Pushbullet(), new Pushover(), new Pushy(), @@ -54,6 +57,7 @@ class Notification { new SMTP(), new Telegram(), new Webhook(), + new Bark(), ]; for (let item of list) { diff --git a/server/server.js b/server/server.js index 3084cad21..324ae6779 100644 --- a/server/server.js +++ b/server/server.js @@ -119,6 +119,7 @@ module.exports.io = io; // Must be after io instantiation const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList, sendInfo } = require("./client"); const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler"); +const databaseSocketHandler = require("./socket-handlers/database-socket-handler"); app.use(express.json()); @@ -644,6 +645,38 @@ exports.entryPage = "dashboard"; } }); + socket.on("getMonitorBeats", async (monitorID, period, callback) => { + try { + checkLogin(socket); + + console.log(`Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`); + + if (period == null) { + throw new Error("Invalid period."); + } + + let list = await R.getAll(` + SELECT * FROM heartbeat + WHERE monitor_id = ? AND + time > DATETIME('now', '-' || ? || ' hours') + ORDER BY time ASC + `, [ + monitorID, + period, + ]); + + callback({ + ok: true, + data: list, + }); + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + // Start or Resume the monitor socket.on("resumeMonitor", async (monitorID, callback) => { try { @@ -1263,6 +1296,7 @@ exports.entryPage = "dashboard"; // Status Page Socket Handler for admin only statusPageSocketHandler(socket); + databaseSocketHandler(socket); debug("added all socket handlers"); diff --git a/server/socket-handlers/database-socket-handler.js b/server/socket-handlers/database-socket-handler.js new file mode 100644 index 000000000..42fdb129c --- /dev/null +++ b/server/socket-handlers/database-socket-handler.js @@ -0,0 +1,37 @@ +const { checkLogin } = require("../util-server"); +const Database = require("../database"); + +module.exports = (socket) => { + + // Post or edit incident + socket.on("getDatabaseSize", async (callback) => { + try { + checkLogin(socket); + callback({ + ok: true, + size: Database.getSize(), + }); + } catch (error) { + callback({ + ok: false, + msg: error.message, + }); + } + }); + + socket.on("shrinkDatabase", async (callback) => { + try { + checkLogin(socket); + Database.shrink(); + callback({ + ok: true, + }); + } catch (error) { + callback({ + ok: false, + msg: error.message, + }); + } + }); + +}; diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue index 0baa9881d..aa209fabe 100644 --- a/src/components/PingChart.vue +++ b/src/components/PingChart.vue @@ -1,16 +1,34 @@ <template> - <LineChart :chart-data="chartData" :options="chartOptions" /> + <div> + <div class="period-options"> + <button type="button" class="btn btn-light dropdown-toggle btn-period-toggle" data-bs-toggle="dropdown" aria-expanded="false"> + {{ chartPeriodOptions[chartPeriodHrs] }}  + </button> + <ul class="dropdown-menu dropdown-menu-end"> + <li v-for="(item, key) in chartPeriodOptions" :key="key"> + <a class="dropdown-item" :class="{ active: chartPeriodHrs == key }" href="#" @click="chartPeriodHrs = key">{{ item }}</a> + </li> + </ul> + </div> + <div class="chart-wrapper" :class="{ loading : loading}"> + <LineChart :chart-data="chartData" :options="chartOptions" /> + </div> + </div> </template> -<script> +<script lang="ts"> import { BarController, BarElement, Chart, Filler, LinearScale, LineController, LineElement, PointElement, TimeScale, Tooltip } from "chart.js"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; import "chartjs-adapter-dayjs"; import { LineChart } from "vue-chart-3"; +import { useToast } from "vue-toastification"; +import { UP, DOWN, PENDING } from "../util.ts"; + dayjs.extend(utc); dayjs.extend(timezone); +const toast = useToast(); Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler); @@ -24,8 +42,23 @@ export default { }, data() { return { + + loading: false, + // Configurable filtering on top of the returned data - chartPeriodHrs: 6, + chartPeriodHrs: 0, + + chartPeriodOptions: { + 0: this.$t("recent"), + 3: "3h", + 6: "6h", + 24: "24h", + 168: "1w", + }, + + // A heartbeatList for 3h, 6h, 24h, 1w + // Uses the $root.heartbeatList when value is null + heartbeatList: null }; }, computed: { @@ -117,7 +150,7 @@ export default { }, callbacks: { label: (context) => { - return ` ${new Intl.NumberFormat().format(context.parsed.y)} ms` + return ` ${new Intl.NumberFormat().format(context.parsed.y)} ms`; }, } }, @@ -125,27 +158,36 @@ export default { display: false, }, }, - } + }; }, chartData() { let pingData = []; // Ping Data for Line Chart, y-axis contains ping time let downData = []; // Down Data for Bar Chart, y-axis is 1 if target is down, 0 if target is up - if (this.monitorId in this.$root.heartbeatList) { - this.$root.heartbeatList[this.monitorId] - .filter( - (beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter(dayjs().subtract(this.chartPeriodHrs, "hours"))) - .map((beat) => { - const x = this.$root.datetime(beat.time); - pingData.push({ - x, - y: beat.ping, - }); - downData.push({ - x, - y: beat.status === 0 ? 1 : 0, - }) + + let heartbeatList = this.heartbeatList || + (this.monitorId in this.$root.heartbeatList && this.$root.heartbeatList[this.monitorId]) || + []; + + heartbeatList + .filter( + // Filtering as data gets appended + // not the most efficient, but works for now + (beat) => dayjs.utc(beat.time).tz(this.$root.timezone).isAfter( + dayjs().subtract(Math.max(this.chartPeriodHrs, 6), "hours") + ) + ) + .map((beat) => { + const x = this.$root.datetime(beat.time); + pingData.push({ + x, + y: beat.ping, }); - } + downData.push({ + x, + y: beat.status === DOWN ? 1 : 0, + }); + }); + return { datasets: [ { @@ -172,5 +214,110 @@ export default { }; }, }, + watch: { + // Update chart data when the selected chart period changes + chartPeriodHrs: function (newPeriod) { + if (newPeriod == "0") { + newPeriod = null; + this.heartbeatList = null; + } else { + this.loading = true; + + this.$root.getMonitorBeats(this.monitorId, newPeriod, (res) => { + if (!res.ok) { + toast.error(res.msg); + } else { + this.heartbeatList = res.data; + } + this.loading = false; + }); + } + } + }, + created() { + // Setup Watcher on the root heartbeatList, + // And mirror latest change to this.heartbeatList + this.$watch(() => this.$root.heartbeatList[this.monitorId], + (heartbeatList) => { + if (this.chartPeriodHrs != 0) { + const newBeat = heartbeatList.at(-1); + if (newBeat && dayjs.utc(newBeat.time) > dayjs.utc(this.heartbeatList.at(-1)?.time)) { + this.heartbeatList.push(heartbeatList.at(-1)); + } + } + }, + { deep: true } + ); + } }; </script> + +<style lang="scss" scoped> +@import "../assets/vars.scss"; + +.form-select { + width: unset; + display: inline-flex; +} + +.period-options { + padding: 0.1em 1em; + margin-bottom: -1.2em; + float: right; + position: relative; + z-index: 10; + + .dropdown-menu { + padding: 0; + min-width: 50px; + font-size: 0.9em; + + .dark & { + background: $dark-bg; + } + + .dropdown-item { + border-radius: 0.3rem; + padding: 2px 16px 4px 16px; + + .dark & { + background: $dark-bg; + } + + .dark &:hover { + background: $dark-font-color; + } + } + + .dark & .dropdown-item.active { + background: $primary; + color: $dark-font-color2; + } + } + + .btn-period-toggle { + padding: 2px 15px; + background: transparent; + border: 0; + color: $link-color; + opacity: 0.7; + font-size: 0.9em; + + &::after { + vertical-align: 0.155em; + } + + .dark & { + color: $dark-font-color; + } + } +} + +.chart-wrapper { + margin-bottom: 0.5em; + + &.loading { + filter: blur(10px); + } +} +</style> diff --git a/src/components/notifications/Bark.vue b/src/components/notifications/Bark.vue new file mode 100644 index 000000000..014450dec --- /dev/null +++ b/src/components/notifications/Bark.vue @@ -0,0 +1,15 @@ +<template> + <div class="mb-3"> + <label for="Bark Endpoint" class="form-label">{{ $t("Bark Endpoint") }}<span style="color: red;"><sup>*</sup></span></label> + <input id="Bark Endpoint" v-model="$parent.notification.barkEndpoint" type="text" class="form-control" required> + <div class="form-text"> + <p><span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}</p> + </div> + <i18n-t tag="div" keypath="wayToGetTeamsURL" class="form-text"> + <a + href="https://github.com/Finb/Bark" + target="_blank" + >{{ $t("here") }}</a> + </i18n-t> + </div> +</template> diff --git a/src/components/notifications/ClickSendSMS.vue b/src/components/notifications/ClickSendSMS.vue new file mode 100644 index 000000000..2aed4184b --- /dev/null +++ b/src/components/notifications/ClickSendSMS.vue @@ -0,0 +1,38 @@ +<template> + <div class="mb-3"> + <label for="clicksendsms-login" class="form-label">API Username</label> + <div class="form-text"> + {{ $t("apiCredentials") }} + <a href="http://dashboard.clicksend.com/account/subaccounts" target="_blank">here</a> + </div> + <input id="clicksendsms-login" v-model="$parent.notification.clicksendsmsLogin" type="text" class="form-control" required> + <label for="clicksendsms-key" class="form-label">API Key</label> + <HiddenInput id="clicksendsms-key" v-model="$parent.notification.clicksendsmsPassword" :required="true" autocomplete="one-time-code"></HiddenInput> + </div> + <div class="mb-3"> + <div class="form-text"> + {{ $t("checkPrice", [$t("clicksendsms")]) }} + <a href="https://www.clicksend.com/us/pricing" target="_blank">https://clicksend.com/us/pricing</a> + </div> + </div> + <div class="mb-3"> + <label for="clicksendsms-to-number" class="form-label">Recipient Number</label> + <input id="clicksendsms-to-number" v-model="$parent.notification.clicksendsmsToNumber" type="text" minlength="8" maxlength="14" class="form-control" required> + </div> + <div class="mb-3"> + <label for="clicksendsms-sender-name" class="form-label">From Name/Number - + <a href="https://help.clicksend.com/article/4kgj7krx00-what-is-a-sender-id-or-sender-number" target="_blank">More Info</a> + </label> + <input id="clicksendsms-sender-name" v-model="$parent.notification.clicksendsmsSenderName" type="text" minlength="3" maxlength="11" class="form-control"> + <div class="form-text">Leave blank to use a shared sender number.</div> + </div> +</template> +<script> +import HiddenInput from "../HiddenInput.vue"; + +export default { + components: { + HiddenInput, + }, +}; +</script> diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 96ee2824b..4b51569a2 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -11,6 +11,7 @@ import Pushover from "./Pushover.vue"; import Pushy from "./Pushy.vue"; import Octopush from "./Octopush.vue"; import PromoSMS from "./PromoSMS.vue"; +import ClickSendSMS from "./ClickSendSMS.vue"; import LunaSea from "./LunaSea.vue"; import Feishu from "./Feishu.vue"; import Apprise from "./Apprise.vue"; @@ -20,6 +21,7 @@ import Mattermost from "./Mattermost.vue"; import Matrix from "./Matrix.vue"; import AliyunSMS from "./AliyunSms.vue"; import DingDing from "./DingDing.vue"; +import Bark from "./Bark.vue"; /** * Manage all notification form. @@ -40,6 +42,7 @@ const NotificationFormList = { "pushy": Pushy, "octopush": Octopush, "promosms": PromoSMS, + "clicksendsms": ClickSendSMS, "lunasea": LunaSea, "Feishu": Feishu, "AliyunSMS": AliyunSMS, @@ -48,7 +51,8 @@ const NotificationFormList = { "line": Line, "mattermost": Mattermost, "matrix": Matrix, - "DingDing": DingDing + "DingDing": DingDing, + "Bark": Bark } export default NotificationFormList diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js index a7be06f1c..d0681cf54 100644 --- a/src/languages/bg-BG.js +++ b/src/languages/bg-BG.js @@ -6,7 +6,7 @@ export default { ignoreTLSError: "Игнорирай TLS/SSL грешки за HTTPS уебсайтове", upsideDownModeDescription: "Обръща статуса от достъпен на недостъпен. Ако услугата е достъпна, ще се вижда като НЕДОСТЪПНА.", maxRedirectDescription: "Максимален брой пренасочвания, които да бъдат следвани. Въведете 0 за да изключите пренасочване.", - acceptedStatusCodesDescription: "Изберете статус кодове, които се считат за успешен отговор.", + acceptedStatusCodesDescription: "Изберете статус кодове, които да се считат за успешен отговор.", passwordNotMatchMsg: "Повторената парола не съвпада.", notificationDescription: "Моля, задайте известието към монитор(и), за да функционира.", keywordDescription: "Търси ключова дума в чист html или JSON отговор - чувствителна е към регистъра", @@ -130,7 +130,7 @@ export default { "Clear Data": "Изтрий данни", Events: "Събития", Heartbeats: "Проверки", - "Auto Get": "Автоматияно получаване", + "Auto Get": "Авт. попълване", backupDescription: "Можете да архивирате всички монитори и всички известия в JSON файл.", backupDescription2: "PS: Данни за история и събития не са включени.", backupDescription3: "Чувствителни данни, като токен кодове за известяване, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.", @@ -199,7 +199,7 @@ export default { "Status Page": "Статус страница", "Primary Base URL": "Основен базов URL адрес", "Push URL": "Генериран Push URL адрес", - needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди.", + needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди", pushOptionalParams: "Допълнителни, но незадължителни параметри: {0}", defaultNotificationName: "Моето {notification} известяване ({number})", here: "тук", @@ -252,14 +252,14 @@ export default { "More info on:": "Повече информация на: {0}", pushoverDesc1: "Приоритет Спешно (2) по подразбиране изчаква 30 секунди между повторните опити и изтича след 1 час.", pushoverDesc2: "Ако желаете да изпратите известявания до различни устройства, попълнете полето Устройство.", - "SMS Type": "СМС тип", + "SMS Type": "SMS тип", octopushTypePremium: "Премиум (Бърз - препоръчителен в случай на тревога)", octopushTypeLowCost: "Евтин (Бавен - понякога бива блокиран от оператора)", checkPrice: "Тарифни планове на {0}:", octopushLegacyHint: "Дали използвате съвместима версия на Octopush (2011-2020) или нова версия?", "Check octopush prices": "Тарифни планове на octopush {0}.", octopushPhoneNumber: "Телефонен номер (в международен формат, например: +33612345678) ", - octopushSMSSender: "СМС подател Име: 3-11 знака - букви, цифри и интервал (a-zA-Z0-9)", + octopushSMSSender: "SMS подател Име: 3-11 знака - букви, цифри и интервал (a-zA-Z0-9)", "LunaSea Device ID": "LunaSea ID на устройство", "Apprise URL": "Apprise URL адрес", "Example:": "Пример: {0}", @@ -280,12 +280,12 @@ export default { aboutIconURL: "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.", aboutMattermostChannelName: "Може да замените канала по подразбиране, към който публикува уеб куката, като въведете името на канала в полето \"Канал име\". Tрябва да бъде активирано в настройките за уеб кука на Mattermost. Например: #other-channel", matrix: "Matrix", - promosmsTypeEco: "СМС ECO - евтин, но бавен. Често е претоварен. Само за получатели от Полша.", - promosmsTypeFlash: "СМС FLASH - Съобщението автоматично се показва на устройството на получателя. Само за получатели от Полша.", - promosmsTypeFull: "СМС FULL - Високо ниво на СМС услуга. Може да използвате Вашето име като подател (Необходимо е първо да регистрирате името). Надежден метод за съобщения тип тревога.", - promosmsTypeSpeed: "СМС SPEED - Най-висок приоритет в системата. Много бърза и надеждна, но същвременно скъпа услуга. (Около два пъти по-висока цена в сравнение с SMS FULL).", + promosmsTypeEco: "SMS ECO - евтин, но бавен. Често е претоварен. Само за получатели от Полша.", + promosmsTypeFlash: "SMS FLASH - Съобщението автоматично се показва на устройството на получателя. Само за получатели от Полша.", + promosmsTypeFull: "SMS FULL - Високо ниво на SMS услуга. Може да използвате Вашето име като подател (Необходимо е първо да регистрирате името). Надежден метод за съобщения тип тревога.", + promosmsTypeSpeed: "SMS SPEED - Най-висок приоритет в системата. Много бърза и надеждна, но същвременно скъпа услуга. (Около два пъти по-висока цена в сравнение с SMS FULL).", promosmsPhoneNumber: "Телефонен номер (за получатели от Полша, може да пропуснете въвеждането на код за населено място)", - promosmsSMSSender: "СМС Подател име: Предварително регистрирано име или някое от имената по подразбиране: InfoSMS, SMS Info, MaxSMS, INFO, SMS", + promosmsSMSSender: "SMS Подател име: Предварително регистрирано име или някое от имената по подразбиране: InfoSMS, SMS Info, MaxSMS, INFO, SMS", "Feishu WebHookUrl": "Feishu URL адрес за уеб кука", matrixHomeserverURL: "Сървър URL адрес (започва с http(s):// и порт по желание)", "Internal Room Id": "ID на вътрешна стая", @@ -297,7 +297,7 @@ export default { PushUrl: "Push URL адрес", HeadersInvalidFormat: "Заявените хедъри не са валидни JSON: ", BodyInvalidFormat: "Заявеното съобщение не е валиден JSON: ", - "Monitor History": "История на мониторите:", + "Monitor History": "История на мониторите", clearDataOlderThan: "Ще се съхранява за {0} дни.", records: "записа", "One record": "Един запис", diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index 5e69899d8..79016835b 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -197,4 +197,112 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", + "Primary Base URL": "Primär URL", + "Push URL": "Push URL", + needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen", + pushOptionalParams: "Optionale Parameter: {0}", + defaultNotificationName: "Meine {notification} Alarm ({number})", + here: "hier", + Required: "Erforderlich", + "Bot Token": "Bot Token", + wayToGetTelegramToken: "Hier kannst du einen Token erhalten {0}.", + "Chat ID": "Chat ID", + supportTelegramChatID: "Unterstützt Direkt Chat / Gruppe / Kanal Chat-ID's", + wayToGetTelegramChatID: "Du kannst die Chat-ID erhalten, indem du eine Nachricht an den Bot sendest und zu dieser URL gehst, um die chat_id: zu sehen.", + "YOUR BOT TOKEN HERE": "HIER DEIN BOT TOKEN", + chatIDNotFound: "Chat-ID wurde nicht gefunden: bitte sende zuerst eine Nachricht an diesen Bot", + "Post URL": "Post URL", + "Content Type": "Content Type", + webhookJsonDesc: "{0} ist gut für alle modernen HTTP-Server sowie Express.js", + webhookFormDataDesc: "{multipart} ist gut für PHP. Die JSON muss mit {decodeFunction} geparst werden", + secureOptionNone: "Keine / STARTTLS (25, 587)", + secureOptionTLS: "TLS (465)", + "Ignore TLS Error": "TLS-Fehler ignorieren", + "From Email": "Von Email", + emailCustomSubject: "Benutzerdefinierter Betreff", + "To Email": "Zu Email", + smtpCC: "CC", + smtpBCC: "BCC", + "Discord Webhook URL": "Discord Webhook URL", + wayToGetDiscordURL: "Du kannst diesen erhalten, indem du zu den Servereinstellungen gehst -> Integrationen -> Neuer Webhook", + "Bot Display Name": "Bot-Anzeigename", + "Prefix Custom Message": "Benutzerdefinierter Nachrichten Präfix", + "Hello @everyone is...": "Hallo {'@'}everyone ist...", + "Webhook URL": "Webhook URL", + wayToGetTeamsURL: "Hier erfährst du, wie eine Webhook-URL erstellt werden kann {0}.", + Number: "Nummer", + Recipients: "Empfänger", + needSignalAPI: "Es wird ein Signal Client mit REST-API benötigt.", + wayToCheckSignalURL: "Du kannst diese URL aufrufen, um zu sehen, wie du eine einrichtest:", + signalImportant: "WICHTIG: Gruppen und Nummern können in Empfängern nicht gemischt werden!", + "Application Token": "Anwendungs Token", + "Server URL": "Server URL", + Priority: "Priorität", + "Icon Emoji": "Icon Emoji", + "Channel Name": "Kanalname", + "Uptime Kuma URL": "Uptime Kuma URL", + aboutWebhooks: "Weitere Informationen zu Webhooks auf: {0}", + aboutChannelName: "Gebe den Kanalnamen ein auf {0} Feld Kanalname, wenn du den Webhook-Kanal umgehen möchtest. Ex: #other-channel", + aboutKumaURL: "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird es standardmäßig die GitHub Projekt Seite verwenden.", + emojiCheatSheet: "Emoji Cheat Sheet: {0}", + "User Key": "Benutzerschlüssel", + Device: "Gerät", + "Message Title": "Nachrichtentitel", + "Notification Sound": "Benachrichtigungston", + "More info on:": "Mehr Infos auf: {0}", + pushoverDesc1: "Notfallpriorität (2) hat Standardmäßig 30 Sekunden Auszeit, zwischen den Versuchen und läuft nach 1 Stunde ab.", + pushoverDesc2: "Fülle das Geräte Feld aus, wenn du Benachrichtigungen an verschiedene Geräte senden möchtest.", + "SMS Type": "SMS Typ", + octopushTypePremium: "Premium (Schnell - zur Benachrichtigung empfohlen)", + octopushTypeLowCost: "Kostengünstig (Langsam - manchmal vom Betreiber gesperrt)", + checkPrice: "Prüfe {0} Preise:", + octopushLegacyHint: "Verwendest du die Legacy-Version von Octopush (2011-2020) oder die neue Version?", + "Check octopush prices": "Überprüfe die Oktopush Preise {0}.", + octopushPhoneNumber: "Telefonnummer (Internationales Format, z.B : +49612345678) ", + octopushSMSSender: "Name des SMS-Absenders : 3-11 alphanumerische Zeichen und Leerzeichen (a-zA-Z0-9)", + "LunaSea Device ID": "LunaSea Geräte ID", + "Apprise URL": "Apprise URL", + "Example:": "Beispiel: {0}", + "Read more:": "Weiterlesen: {0}", + "Status:": "Status: {0}", + "Read more": "Weiterlesen", + appriseInstalled: "Apprise ist installiert.", + appriseNotInstalled: "Apprise ist nicht installiert. {0}", + "Access Token": "Access Token", + "Channel access token": "Channel access token", + "Line Developers Console": "Line Developers Console", + lineDevConsoleTo: "Line Developers Console - {0}", + "Basic Settings": "Basic Settings", + "User ID": "User ID", + "Messaging API": "Messaging API", + wayToGetLineChannelToken: "Rufe zuerst {0} auf, erstelle dann einen Provider und Channel (Messaging API). Als nächstes kannst du den Channel access token und die User ID aus den oben genannten Menüpunkten abrufen.", + "Icon URL": "Icon URL", + aboutIconURL: "Du kannst einen Link zu einem Bild in 'Icon URL' übergeben um das Standardprofilbild zu überschreiben. Wird nicht verwendet, wenn ein Icon Emoji gesetzt ist.", + aboutMattermostChannelName: "Du kannst den Standardkanal, auf dem der Webhook postet überschreiben, indem der Kanalnamen in das Feld 'Channel Name' eingeben wird. Dies muss in den Mattermost Webhook-Einstellungen aktiviert werden. Ex: #other-channel", + matrix: "Matrix", + promosmsTypeEco: "SMS ECO - billig, aber langsam und oft überladen. Nur auf polnische Empfänger beschränkt.", + promosmsTypeFlash: "SMS FLASH - Die Nachricht wird automatisch auf dem Empfängergerät angezeigt. Nur auf polnische Empfänger beschränkt.", + promosmsTypeFull: "SMS FULL - Premium Stufe von SMS, es kann der Absendernamen verwendet werden (Der Name musst zuerst registriert werden). Zuverlässig für Warnungen.", + promosmsTypeSpeed: "SMS SPEED - Höchste Priorität im System. Sehr schnell und zuverlässig, aber teuer (Ungefähr das doppelte von SMS FULL).", + promosmsPhoneNumber: "Phone number (Für polnische Empfänger können die Vorwahlen übersprungen werden)", + promosmsSMSSender: "Name des SMS-Absenders : vorregistrierter Name oder einer der Standardwerte: InfoSMS, SMS Info, MaxSMS, INFO, SMS", + "Feishu WebHookUrl": "Feishu Webhook URL", + matrixHomeserverURL: "Heimserver URL (mit http(s):// und optionalen Ports)", + "Internal Room Id": "Interne Raum-ID", + matrixDesc1: "Die interne Raum-ID findest du im erweiterten Bereich der Raumeinstellungen im Matrix-Client. Es sollte es aussehen wie z.B. !QMdRCpUIfLwsfjxye6:home.server.", + matrixDesc2: "Es wird dringend empfohlen, dass ein neuen Benutzer erstellt wird und nicht den Zugriffstoken deines eigenen Matrix-Benutzers verwendest. Anderfalls ermöglicht es vollen Zugriff auf dein Konto und alle Räume, denen du beigetreten bist. Erstelle stattdessen einen neuen Benutzer und lade ihn nur in den Raum ein, in dem du die Benachrichtigung erhalten möchtest. Du kannst den Zugriffstoken erhalten, indem du folgendes ausführst {0}", + Method: "Method", + Body: "Body", + Headers: "Headers", + PushUrl: "Push URL", + HeadersInvalidFormat: "Die Header ist kein gültiges JSON: ", + BodyInvalidFormat: "Der Body ist kein gültiges JSON: ", + "Monitor History": "Monitor Verlauf", + clearDataOlderThan: "Bewahre die Monitor-Verlaufsdaten für {0} Tage auf.", + PasswordsDoNotMatch: "Passwörter stimmen nicht überein.", + records: "Einträge", + "One record": "Ein Eintrag", + "Showing {from} to {to} of {count} records": "Zeige {from} zu {to} von {count} Einträge", + steamApiKeyDescription: "Um einen Steam Game Server zu überwachen, wird ein Steam Web-API-Schlüssel benötigt. Dieser kann hier registriert werden: ", + "Current User": "Aktueller Benutzer", }; diff --git a/src/languages/en.js b/src/languages/en.js index d3a69c191..87b96d1af 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -183,11 +183,10 @@ export default { "Edit Status Page": "Edit Status Page", "Go to Dashboard": "Go to Dashboard", "Status Page": "Status Page", - // Start notification form defaultNotificationName: "My {notification} Alert ({number})", here: "here", - "Required": "Required", - "telegram": "Telegram", + Required: "Required", + telegram: "Telegram", "Bot Token": "Bot Token", wayToGetTelegramToken: "You can get a token from {0}.", "Chat ID": "Chat ID", @@ -195,12 +194,12 @@ export default { wayToGetTelegramChatID: "You can get your chat ID by sending a message to the bot and going to this URL to view the chat_id:", "YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE", chatIDNotFound: "Chat ID is not found; please send a message to this bot first", - "webhook": "Webhook", + webhook: "Webhook", "Post URL": "Post URL", "Content Type": "Content Type", 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}", - "smtp": "Email (SMTP)", + smtp: "Email (SMTP)", secureOptionNone: "None / STARTTLS (25, 587)", secureOptionTLS: "TLS (465)", "Ignore TLS Error": "Ignore TLS Error", @@ -209,26 +208,26 @@ export default { "To Email": "To Email", smtpCC: "CC", smtpBCC: "BCC", - "discord": "Discord", + discord: "Discord", "Discord Webhook URL": "Discord Webhook URL", wayToGetDiscordURL: "You can get this by going to Server Settings -> Integrations -> Create Webhook", "Bot Display Name": "Bot Display Name", "Prefix Custom Message": "Prefix Custom Message", "Hello @everyone is...": "Hello {'@'}everyone is...", - "teams": "Microsoft Teams", + teams: "Microsoft Teams", "Webhook URL": "Webhook URL", wayToGetTeamsURL: "You can learn how to create a webhook URL {0}.", - "signal": "Signal", - "Number": "Number", - "Recipients": "Recipients", + signal: "Signal", + Number: "Number", + Recipients: "Recipients", needSignalAPI: "You need to have a signal client with REST API.", wayToCheckSignalURL: "You can check this URL to view how to set one up:", signalImportant: "IMPORTANT: You cannot mix groups and numbers in recipients!", - "gotify": "Gotify", + gotify: "Gotify", "Application Token": "Application Token", "Server URL": "Server URL", - "Priority": "Priority", - "slack": "Slack", + Priority: "Priority", + slack: "Slack", "Icon Emoji": "Icon Emoji", "Channel Name": "Channel Name", "Uptime Kuma URL": "Uptime Kuma URL", @@ -241,13 +240,14 @@ export default { pushy: "Pushy", octopush: "Octopush", promosms: "PromoSMS", + clicksendsms: "ClickSend SMS", lunasea: "LunaSea", apprise: "Apprise (Support 50+ Notification services)", pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", "User Key": "User Key", - "Device": "Device", + Device: "Device", "Message Title": "Message Title", "Notification Sound": "Notification Sound", "More info on:": "More info on: {0}", @@ -257,6 +257,7 @@ export default { octopushTypePremium: "Premium (Fast - recommended for alerting)", octopushTypeLowCost: "Low Cost (Slow - sometimes blocked by operator)", checkPrice: "Check {0} prices:", + apiCredentials: "API credentials", octopushLegacyHint: "Do you use the legacy version of Octopush (2011-2020) or the new version?", "Check octopush prices": "Check octopush prices {0}.", octopushPhoneNumber: "Phone number (intl format, eg : +33612345678) ", @@ -280,7 +281,7 @@ export default { "Icon URL": "Icon URL", aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.", aboutMattermostChannelName: "You can override the default channel that the Webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in the Mattermost Webhook settings. Ex: #other-channel", - "matrix": "Matrix", + matrix: "Matrix", promosmsTypeEco: "SMS ECO - cheap but slow and often overloaded. Limited only to Polish recipients.", promosmsTypeFlash: "SMS FLASH - Message will automatically show on recipient device. Limited only to Polish recipients.", promosmsTypeFull: "SMS FULL - Premium tier of SMS, You can use your Sender Name (You need to register name first). Reliable for alerts.", @@ -292,18 +293,18 @@ export default { "Internal Room Id": "Internal Room ID", matrixDesc1: "You can find the internal room ID by looking in the advanced section of the room settings in your Matrix client. It should look like !QMdRCpUIfLwsfjxye6:home.server.", matrixDesc2: "It is highly recommended you create a new user and do not use your own Matrix user's access token as it will allow full access to your account and all the rooms you joined. Instead, create a new user and only invite it to the room that you want to receive the notification in. You can get the access token by running {0}", - // End notification form Method: "Method", Body: "Body", Headers: "Headers", PushUrl: "Push URL", HeadersInvalidFormat: "The request headers are not valid JSON: ", BodyInvalidFormat: "The request body is not valid JSON: ", - "Monitor History": "Monitor History:", + "Monitor History": "Monitor History", clearDataOlderThan: "Keep monitor history data for {0} days.", PasswordsDoNotMatch: "Passwords do not match.", records: "records", "One record": "One record", "Showing {from} to {to} of {count} records": "Showing {from} to {to} of {count} records", steamApiKeyDescription: "For monitoring a Steam Game Server you need a Steam Web-API key. You can register your API key here: ", + "Current User": "Current User", }; diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js index ccd42c8f0..2f238cdce 100644 --- a/src/languages/es-ES.js +++ b/src/languages/es-ES.js @@ -198,7 +198,7 @@ export default { pushbullet: "Pushbullet", line: "Line Messenger", mattermost: "Mattermost", - "Monitor History": "Historial de monitor:", + "Monitor History": "Historial de monitor", clearDataOlderThan: "Mantener los datos del historial del monitor durante {0} días.", records: "registros", "One record": "Un registro", diff --git a/src/languages/fr-FR.js b/src/languages/fr-FR.js index 22c656b35..062435d73 100644 --- a/src/languages/fr-FR.js +++ b/src/languages/fr-FR.js @@ -179,11 +179,10 @@ export default { "Edit Status Page": "Modifier la page de statut", "Go to Dashboard": "Accéder au tableau de bord", "Status Page": "Status Page", - // Start notification form defaultNotificationName: "Ma notification {notification} numéro ({number})", here: "ici", - "Required": "Requis", - "telegram": "Telegram", + Required: "Requis", + telegram: "Telegram", "Bot Token": "Bot Token", wayToGetTelegramToken: "Vous pouvez obtenir un token depuis {0}.", "Chat ID": "Chat ID", @@ -191,12 +190,12 @@ export default { wayToGetTelegramChatID: "Vous pouvez obtenir l'ID du chat en envoyant un message avec le bot puis en récupérant l'URL pour voir l'ID du salon :", "YOUR BOT TOKEN HERE": "VOTRE TOKEN BOT ICI", chatIDNotFound: "ID du salon introuvable, envoyez un message via le bot avant", - "webhook": "Webhook", + webhook: "Webhook", "Post URL": "Post URL", "Content Type": "Content Type", webhookJsonDesc: "{0} est bien/bon pour tous les serveurs HTTP modernes comme express.js", webhookFormDataDesc: "{multipart} est bien/bon pour du PHP, vous avez juste besoin de mettre le json via/depuis {decodeFunction}", - "smtp": "Email (SMTP)", + smtp: "Email (SMTP)", secureOptionNone: "Aucun / STARTTLS (25, 587)", secureOptionTLS: "TLS (465)", "Ignore TLS Error": "Ignorer les erreurs TLS", @@ -204,26 +203,26 @@ export default { "To Email": "Vers l'Email", smtpCC: "CC", smtpBCC: "BCC", - "discord": "Discord", + discord: "Discord", "Discord Webhook URL": "Discord Webhook URL", wayToGetDiscordURL: "Vous pouvez l'obtenir en allant dans 'Paramètres du Serveur' -> 'Intégrations' -> 'Créer un Webhook'", "Bot Display Name": "Nom du bot (affiché)", "Prefix Custom Message": "Prefix Custom Message", "Hello @everyone is...": "Bonjour {'@'}everyone il...", - "teams": "Microsoft Teams", + teams: "Microsoft Teams", "Webhook URL": "Webhook URL", wayToGetTeamsURL: "Vous pouvez apprendre comment créer un Webhook {0}.", - "signal": "Signal", - "Number": "Numéro", - "Recipients": "Destinataires", + signal: "Signal", + Number: "Numéro", + Recipients: "Destinataires", needSignalAPI: "Vous avez besoin d'un client Signal avec l'API REST.", wayToCheckSignalURL: "Vous pouvez regarder l'URL sur comment le mettre en place :", signalImportant: "IMPORTANT: Vous ne pouvez pas mixer les groupes et les numéros en destinataires !", - "gotify": "Gotify", + gotify: "Gotify", "Application Token": "Application Token", "Server URL": "Server URL", - "Priority": "Priorité", - "slack": "Slack", + Priority: "Priorité", + slack: "Slack", "Icon Emoji": "Icon Emoji", "Channel Name": "Nom du salon", "Uptime Kuma URL": "Uptime Kuma URL", @@ -242,7 +241,7 @@ export default { line: "Line Messenger", mattermost: "Mattermost", "User Key": "Clé d'utilisateur", - "Device": "Appareil", + Device: "Appareil", "Message Title": "Titre du message", "Notification Sound": "Son de notification", "More info on:": "Plus d'informations sur: {0}", @@ -273,12 +272,11 @@ export default { "Icon URL": "Icon URL", aboutIconURL: "Vous pouvez mettre un lien vers l'image dans \"Icon URL\" pour remplacer l'image de profil par défaut. Ne sera pas utilisé si Icon Emoji est défini.", aboutMattermostChannelName: "Vous pouvez remplacer le salon par défaut que le Webhook utilise en mettant le nom du salon dans le champ \"Channel Name\". Vous aurez besoin de l'activer depuis les paramètres de Mattermost. Ex : #autre-salon", - "matrix": "Matrix", + matrix: "Matrix", promosmsTypeEco: "SMS ECO - Pas cher mais lent et souvent surchargé. Limité uniquement aux déstinataires Polonais.", promosmsTypeFlash: "SMS FLASH - Le message sera automatiquement affiché sur l'appareil du destinataire. Limité uniquement aux déstinataires Polonais.", promosmsTypeFull: "SMS FULL - Version Premium des SMS, Vous pouvez mettre le nom de l'expéditeur (Vous devez vous enregistrer avant). Fiable pour les alertes.", promosmsTypeSpeed: "SMS SPEED - La plus haute des priorités dans le système. Très rapide et fiable mais cher (environ le double du prix d'un SMS FULL).", promosmsPhoneNumber: "Numéro de téléphone (Poiur les déstinataires Polonais, vous pouvez enlever les codes interna.)", promosmsSMSSender: "SMS Expéditeur : Nom pré-enregistré ou l'un de base: InfoSMS, SMS Info, MaxSMS, INFO, SMS", - // End notification form }; diff --git a/src/languages/id-ID.js b/src/languages/id-ID.js index 5cb38ea6d..5bad2a7e5 100644 --- a/src/languages/id-ID.js +++ b/src/languages/id-ID.js @@ -179,11 +179,10 @@ export default { "Edit Status Page": "Edit Halaman Status", "Go to Dashboard": "Pergi ke Dasbor", "Status Page": "Halaman Status", - // Start notification form defaultNotificationName: "{notification} saya Peringatan ({number})", here: "di sini", - "Required": "Dibutuhkan", - "telegram": "Telegram", + Required: "Dibutuhkan", + telegram: "Telegram", "Bot Token": "Bot Token", "You can get a token from": "Anda bisa mendapatkan token dari", "Chat ID": "Chat ID", @@ -191,12 +190,12 @@ export default { wayToGetTelegramChatID: "Anda bisa mendapatkan chat id Anda dengan mengirim pesan ke bot dan pergi ke url ini untuk melihat chat_id:", "YOUR BOT TOKEN HERE": "BOT TOKEN ANDA DI SINI", chatIDNotFound: "Chat ID tidak ditemukan, tolong kirim pesan ke bot ini dulu", - "webhook": "Webhook", + webhook: "Webhook", "Post URL": "Post URL", "Content Type": "Tipe konten", webhookJsonDesc: "{0} bagus untuk peladen http modern seperti express.js", webhookFormDataDesc: "{multipart} bagus untuk PHP, Anda hanya perlu mengurai json dengan {decodeFunction}", - "smtp": "Surel (SMTP)", + smtp: "Surel (SMTP)", secureOptionNone: "None / STARTTLS (25, 587)", secureOptionTLS: "TLS (465)", "Ignore TLS Error": "Abaikan Kesalahan TLS", @@ -204,26 +203,26 @@ export default { "To Email": "Ke Surel", smtpCC: "CC", smtpBCC: "BCC", - "discord": "Discord", + discord: "Discord", "Discord Webhook URL": "Discord Webhook URL", wayToGetDiscordURL: "Anda bisa mendapatkan ini dengan pergi ke Server Settings -> Integrations -> Create Webhook", "Bot Display Name": "Nama Bot", "Prefix Custom Message": "Awalan Pesan", "Hello @everyone is...": "Halo {'@'}everyone is...", - "teams": "Microsoft Teams", + teams: "Microsoft Teams", "Webhook URL": "Webhook URL", wayToGetTeamsURL: "Anda dapat mempelajari cara membuat url webhook {0}.", - "signal": "Sinyal", - "Number": "Nomer", - "Recipients": "Penerima", + signal: "Sinyal", + Number: "Nomer", + Recipients: "Penerima", needSignalAPI: "Anda harus memiliki klien sinyal dengan REST API.", wayToCheckSignalURL: "Anda dapat memeriksa url ini untuk melihat cara menyiapkannya:", signalImportant: "PENTING: Anda tidak dapat mencampur grup dan nomor di penerima!", - "gotify": "Gotify", + gotify: "Gotify", "Application Token": "Token Aplikasi", "Server URL": "URL Peladen", - "Priority": "Prioritas", - "slack": "Slack", + Priority: "Prioritas", + slack: "Slack", "Icon Emoji": "Ikon Emoji", "Channel Name": "Nama Saluran", "Uptime Kuma URL": "Uptime Kuma URL", @@ -242,7 +241,7 @@ export default { line: "Line Messenger", mattermost: "Mattermost", "User Key": "Kunci pengguna", - "Device": "Perangkat", + Device: "Perangkat", "Message Title": "Judul Pesan", "Notification Sound": "Suara Nofifikasi", "More info on:": "Info lebih lanjut tentang: {0}", @@ -273,7 +272,7 @@ export default { "Icon URL": "Icon URL", aboutIconURL: "Anda dapat memberikan tautan ke gambar di \"Icon URL\" untuk mengganti gambar profil bawaan. Tidak akan digunakan jika Ikon Emoji diset.", aboutMattermostChannelName: "Anda dapat mengganti saluran bawaan tujuan posting webhook dengan memasukkan nama saluran ke dalam Kolom \"Channel Name\". Ini perlu diaktifkan di pengaturan webhook Mattermost. contoh: #other-channel", - "matrix": "Matrix", + matrix: "Matrix", promosmsTypeEco: "SMS ECO - murah tapi lambat dan sering kelebihan beban. Terbatas hanya untuk penerima Polandia.", promosmsTypeFlash: "SMS FLASH - Pesan akan otomatis muncul di perangkat penerima. Terbatas hanya untuk penerima Polandia.", promosmsTypeFull: "SMS FULL - SMS tingkat premium, Anda dapat menggunakan Nama Pengirim Anda (Anda harus mendaftarkan nama terlebih dahulu). Dapat diAndalkan untuk peringatan.", @@ -281,5 +280,4 @@ export default { promosmsPhoneNumber: "Nomor telepon (untuk penerima Polandia Anda dapat melewati kode area)", promosmsSMSSender: "Nama Pengirim SMS : Nama pra-registrasi atau salah satu bawaan: InfoSMS, Info SMS, MaxSMS, INFO, SMS", "Feishu WebHookUrl": "Feishu WebHookUrl", - // End notification form }; diff --git a/src/languages/nb-NO.js b/src/languages/nb-NO.js index 50b3a5348..0e566a01c 100644 --- a/src/languages/nb-NO.js +++ b/src/languages/nb-NO.js @@ -179,11 +179,10 @@ export default { "Edit Status Page": "Rediger statusside", "Go to Dashboard": "Gå til Dashboard", "Status Page": "Statusside", - // Start notification form defaultNotificationName: "Min {notification} varsling ({number})", here: "here", - "Required": "Obligatorisk", - "telegram": "Telegram", + Required: "Obligatorisk", + telegram: "Telegram", "Bot Token": "Bot Token", wayToGetTelegramToken: "Du kan få et token fra {0}.", "Chat ID": "Chat ID", @@ -191,12 +190,12 @@ export default { wayToGetTelegramChatID: "Du kan få chat-ID-en din ved å sende meldingen til boten og gå til denne nettadressen for å se chat_id:", "YOUR BOT TOKEN HERE": "DITT BOT TOKEN HER", chatIDNotFound: "Chat-ID ble ikke funnet. Send en melding til denne boten først", - "webhook": "Webhook", + webhook: "Webhook", "Post URL": "Post URL", "Content Type": "Content Type", webhookJsonDesc: "{0} er bra for alle moderne HTTP-servere som express.js", webhookFormDataDesc: "{multipart} er bra for PHP, du trenger bare å analysere JSON etter {decodeFunction}", - "smtp": "E-post (SMTP)", + smtp: "E-post (SMTP)", secureOptionNone: "None / STARTTLS (25, 587)", secureOptionTLS: "TLS (465)", "Ignore TLS Error": "Ignorer TLS feilmelding", @@ -204,26 +203,26 @@ export default { "To Email": "Til E-post", smtpCC: "CC", smtpBCC: "BCC", - "discord": "Discord", + discord: "Discord", "Discord Webhook URL": "Discord Webhook URL", wayToGetDiscordURL: "Du kan få dette ved å gå til Serverinnstillinger -> Integrasjoner -> Webhooks -> Ny webhook", "Bot Display Name": "Bot Visningsnavn", "Prefix Custom Message": "Prefiks tilpasset melding", "Hello @everyone is...": "Hei {'@'}everyone det er...", - "teams": "Microsoft Teams", + teams: "Microsoft Teams", "Webhook URL": "Webhook URL", wayToGetTeamsURL: "Du kan lære hvordan du oppretter en webhook-URL {0}.", - "signal": "Signal", - "Number": "Nummer", - "Recipients": "Mottakere", + signal: "Signal", + Number: "Nummer", + Recipients: "Mottakere", needSignalAPI: "Du må ha en Signal-klient med REST API.", wayToCheckSignalURL: "Du kan sjekke denne nettadressen for å se hvordan du konfigurerer en:", signalImportant: "VIKTIG: Du kan ikke blande grupper og nummere i mottakere!", - "gotify": "Gotify", + gotify: "Gotify", "Application Token": "Application Token", "Server URL": "Server URL", - "Priority": "Prioritet", - "slack": "Slack", + Priority: "Prioritet", + slack: "Slack", "Icon Emoji": "Icon Emoji", "Channel Name": "Kanal navn", "Uptime Kuma URL": "Uptime Kuma URL", @@ -242,7 +241,7 @@ export default { line: "Line Messenger", mattermost: "Mattermost", "User Key": "User Key", - "Device": "Device", + Device: "Device", "Message Title": "Message Title", "Notification Sound": "Notification Sound", "More info on:": "More info on: {0}", @@ -273,12 +272,11 @@ export default { "Icon URL": "Icon URL", aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.", aboutMattermostChannelName: "You can override the default channel that webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in Mattermost webhook settings. Ex: #other-channel", - "matrix": "Matrix", + matrix: "Matrix", promosmsTypeEco: "SMS ECO - cheap but slow and often overloaded. Limited only to Polish recipients.", promosmsTypeFlash: "SMS FLASH - Message will automatically show on recipient device. Limited only to Polish recipients.", promosmsTypeFull: "SMS FULL - Premium tier of SMS, You can use Your Sender Name (You need to register name first). Reliable for alerts.", promosmsTypeSpeed: "SMS SPEED - Highest priority in system. Very quick and reliable but costly (about twice of SMS FULL price).", promosmsPhoneNumber: "Phone number (for Polish recipient You can skip area codes)", promosmsSMSSender: "SMS Sender Name : Pre-registred name or one of defaults: InfoSMS, SMS Info, MaxSMS, INFO, SMS", - // End notification form }; diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js index 8af03200d..818893af6 100644 --- a/src/languages/nl-NL.js +++ b/src/languages/nl-NL.js @@ -203,5 +203,5 @@ export default { Headers: "Headers", PushUrl: "Push URL", HeadersInvalidFormat: "The request headers is geen geldige JSON: ", - BodyInvalidFormat: "De request body is geen geldige JSON: " + BodyInvalidFormat: "De request body is geen geldige JSON: ", }; diff --git a/src/languages/pl.js b/src/languages/pl.js index 2861ed0f8..b71885551 100644 --- a/src/languages/pl.js +++ b/src/languages/pl.js @@ -118,8 +118,8 @@ export default { "Last Result": "Ostatni wynik", "Create your admin account": "Utwórz swoje konto administratora", "Repeat Password": "Powtórz hasło", - "Import Backup": "Importuj Kopię", - "Export Backup": "Eksportuj Kopię", + "Import Backup": "Importuj kopię zapasową", + "Export Backup": "Eksportuj kopię zapasową", Export: "Eksportuj", Import: "Importuj", respTime: "Czas Odp. (ms)", @@ -127,7 +127,7 @@ export default { "Default enabled": "Włącz domyślnie", "Apply on all existing monitors": "Zastosuj do istniejących monitorów", Create: "Stwórz", - "Clear Data": "Usuń Dane", + "Clear Data": "Usuń dane", Events: "Wydarzenia", Heartbeats: "Bicia serca", "Auto Get": "Wykryj", @@ -179,11 +179,10 @@ export default { "Edit Status Page": "Edytuj stronę statusu", "Go to Dashboard": "Idź do panelu", "Status Page": "Strona statusu", - // Start notification form defaultNotificationName: "Moje powiadomienie {notification} ({number})", here: "tutaj", - "Required": "Wymagane", - "telegram": "Telegram", + Required: "Wymagane", + telegram: "Telegram", "Bot Token": "Token Bota", wayToGetTelegramToken: "Token można uzyskać z {0}.", "Chat ID": "Identyfikator Czatu", @@ -191,12 +190,12 @@ export default { wayToGetTelegramChatID: "Możesz uzyskać swój identyfikator czatu, wysyłając wiadomość do bota i przechodząc pod ten adres URL, aby wyświetlić identyfikator czatu:", "YOUR BOT TOKEN HERE": "TWOJ TOKEN BOTA", chatIDNotFound: "Identyfikator czatu nie znaleziony, najpierw napisz do bota", - "webhook": "Webhook", + webhook: "Webhook", "Post URL": "Adres URL", "Content Type": "Rodzaj danych", webhookJsonDesc: "{0} jest dobry w przypadku serwerów HTTP, takich jak express.js", webhookFormDataDesc: "{multipart} jest dobry dla PHP, musisz jedynie przetowrzyć dane przez {decodeFunction}", - "smtp": "Email (SMTP)", + smtp: "Email (SMTP)", secureOptionNone: "Brak / STARTTLS (25, 587)", secureOptionTLS: "TLS (465)", "Ignore TLS Error": "Zignrouj Błędy TLS", @@ -204,26 +203,26 @@ export default { "To Email": "Odbiorca (DO)", smtpCC: "DW", smtpBCC: "UDW", - "discord": "Discord", + discord: "Discord", "Discord Webhook URL": "URL Webhook Discorda", wayToGetDiscordURL: "Możesz go uzyskać przechodząc do Ustawienia Serwera -> Integracje -> Tworzenie Webhooka", "Bot Display Name": "Wyświetlana Nazwa Bota", "Prefix Custom Message": "Własny Początek Wiadomości", "Hello @everyone is...": "Hej {'@'}everyone ...", - "teams": "Microsoft Teams", + teams: "Microsoft Teams", "Webhook URL": "URL Webhooka", wayToGetTeamsURL: "You can learn how to create a webhook url {0}.", - "signal": "Signal", - "Number": "Numer", - "Recipients": "Odbiorcy", + signal: "Signal", + Number: "Numer", + Recipients: "Odbiorcy", needSignalAPI: "Musisz posiadać klienta Signal z REST API.", wayToCheckSignalURL: "W celu dowiedzenia się, jak go skonfigurować, odwiedź poniższy link:", signalImportant: "UWAGA: Nie można mieszać nazw grup i numerów odbiorców!", - "gotify": "Gotify", + gotify: "Gotify", "Application Token": "Token Aplikacji", "Server URL": "Server URL", - "Priority": "Priorytet", - "slack": "Slack", + Priority: "Priorytet", + slack: "Slack", "Icon Emoji": "Ikona Emoji", "Channel Name": "Nazwa Kanału", "Uptime Kuma URL": "Adres Uptime Kuma", @@ -242,7 +241,7 @@ export default { line: "Line Messenger", mattermost: "Mattermost", "User Key": "Klucz Użytkownika", - "Device": "Urządzenie", + Device: "Urządzenie", "Message Title": "Tytuł Wiadomości", "Notification Sound": "Dźwięk Powiadomienia", "More info on:": "Więcej informacji na: {0}", @@ -271,14 +270,38 @@ export default { "Messaging API": "API Wiadomości", wayToGetLineChannelToken: "Najpierw uzyskaj dostęp do {0}, utwórz dostawcę i kanał (Messaging API), a następnie możesz uzyskać token dostępu do kanału i identyfikator użytkownika z wyżej wymienionych pozycji menu.", "Icon URL": "Adres Ikony", - aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.", - aboutMattermostChannelName: "You can override the default channel that webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in Mattermost webhook settings. Ex: #other-channel", - "matrix": "Matrix", + aboutIconURL: "Możesz podać link do zdjęcia w \"Adres URL ikony\", aby zastąpić domyślne zdjęcie profilowe. Nie będzie używany, jeśli ustawiona jest ikona Emoji.", + aboutMattermostChannelName: "Możesz zastąpić domyślny kanał, na którym publikowane są posty webhooka, wpisując nazwę kanału w polu \"Nazwa Kanału\". Należy to włączyć w ustawieniach webhooka Mattermost. Np.: #inny-kanał", + matrix: "Matrix", promosmsTypeEco: "SMS ECO - Tanie, lecz wolne. Dostępne tylko w Polsce", promosmsTypeFlash: "SMS FLASH - Wiadomość automatycznie wyświetli się na urządzeniu. Dostępne tylko w Polsce.", promosmsTypeFull: "SMS FULL - Szybkie i dostępne międzynarodowo. Wersja premium usługi, która pozwala min. ustawić własną nazwę nadawcy.", promosmsTypeSpeed: "SMS SPEED - Wysyłka priorytetowa, posiada wszystkie zalety SMS FULL", promosmsPhoneNumber: "Numer Odbiorcy", promosmsSMSSender: "Nadawca SMS (Wcześniej zatwierdzone nazwy z panelu PromoSMS)", - // End notification form + "Primary Base URL": "Główny URL", + "Push URL": "Push URL", + needPushEvery: "Powinieneś wywoływać ten URL co {0} sekund", + pushOptionalParams: "Parametry opcjonalne: {0}", + emailCustomSubject: "Niestandardowy temat", + checkPrice: "Sprawdź ceny {0}:", + octopushLegacyHint: "Czy używasz starszej wersji Octopush (2011-2020) czy nowej wersji?", + "Feishu WebHookUrl": "Feishu WebHookURL", + matrixHomeserverURL: "Adres URL serwera domowego (z http(s):// i opcjonalnie port)", + "Internal Room Id": "Wewnętrzne ID pokoju", + matrixDesc1: "Możesz znaleźć wewnętrzne ID pokoju patrząc w zaawansowanej sekcji ustawień pokoju w twoim kliencie Matrix. Powinien on wyglądać jak !QMdRCpUIfLwsfjxye6:home.server.", + matrixDesc2: "Jest wysoce zalecane, abyś stworzył nowego użytkownika i nie używał tokena dostępu swojego użytkownika Matrix, ponieważ pozwoli on na pełny dostęp do twojego konta i wszystkich pokoi, do których dołączyłeś. Zamiast tego, utwórz nowego użytkownika i zaproś go tylko do pokoju, w którym chcesz otrzymywać powiadomienia. Możesz uzyskać token dostępu przez uruchomienie {0}", + Method: "Metoda", + Body: "Treść", + Headers: "Nagłówki", + PushUrl: "Push URL", + HeadersInvalidFormat: "Nagłówki żądania nie są w poprawnym formacie JSON: ", + BodyInvalidFormat: "Treść żądania nie jest w poprawnym formacie JSON: ", + "Monitor History": "Historia monitorów", + clearDataOlderThan: "Przechowuj dane dotyczące historii monitorowania {0} dni.", + PasswordsDoNotMatch: "Hasła nie pasują.", + records: "rekordy", + "One record": "Jeden rekord", + "Showing {from} to {to} of {count} records": "Wyświetlanie {from} do {to} z {count} rekordów", + steamApiKeyDescription: "Do monitorowania serwera gier Steam potrzebny jest klucz Steam Web-API. Możesz zarejestrować swój klucz API tutaj: ", }; diff --git a/src/languages/ru-RU.js b/src/languages/ru-RU.js index bf4d30860..1b0da54fd 100644 --- a/src/languages/ru-RU.js +++ b/src/languages/ru-RU.js @@ -204,7 +204,7 @@ export default { mattermost: "Mattermost", "Primary Base URL": "Основной URL", "Push URL": "URL пуша", - needPushEvery: "К этому URL необходимо обращаться каждые {0} секунд.", + needPushEvery: "К этому URL необходимо обращаться каждые {0} секунд", pushOptionalParams: "Опциональные параметры: {0}", defaultNotificationName: "Моё уведомление {notification} ({number})", here: "здесь", diff --git a/src/languages/vi.js b/src/languages/vi.js index c47ebe024..0bfa3f208 100644 --- a/src/languages/vi.js +++ b/src/languages/vi.js @@ -1,285 +1,283 @@ -export default { - languageName: "Vietnamese", - checkEverySecond: "Kiểm tra mỗi {0} giây.", - retryCheckEverySecond: "Thử lại mỗi {0} giây.", - retriesDescription: "Số lần thử lại tối đa trước khi dịch vụ được đánh dấu là down và gửi thông báo.", - ignoreTLSError: "Bỏ qua lỗi TLS/SSL với các web HTTPS.", - upsideDownModeDescription: "Trạng thái đảo ngược, nếu dịch vụ có thể truy cập được nghĩa là DOWN.", - maxRedirectDescription: "Số lần chuyển hướng (redirect) tối đa. Đặt thành 0 để tắt chuyển hướng", - acceptedStatusCodesDescription: "Chọn mã code trạng thái được coi là phản hồi thành công.", - passwordNotMatchMsg: "Mật khẩu nhập lại không khớp.", - notificationDescription: "Vui lòng chỉ định một kênh thông báo.", - keywordDescription: "Từ khoá tìm kiếm phản hồi ở dạng html hoặc JSON, có phân biệt chữ HOA - thường", - pauseDashboardHome: "Tạm dừng", - deleteMonitorMsg: "Bạn chắc chắn muốn xóa monitor này chứ?", - deleteNotificationMsg: "Bạn có chắc chắn muốn xóa kênh thông báo này cho tất cả monitor?", - resoverserverDescription: "Cloudflare là máy chủ mặc định, bạn có thể thay đổi bất cứ lúc nào.", - rrtypeDescription: "Hãy chọn RR-Type mà bạn muốn giám sát", - pauseMonitorMsg: "Bạn chắc chắn muốn tạm dừng chứ?", - enableDefaultNotificationDescription: "Bật làm mặc định cho mọi monitor mới về sau. Bạn vẫn có thể tắt thông báo riêng cho từng monitor.", - clearEventsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ sự kiện cho monitor này chứ?", - clearHeartbeatsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ heartbeats cho monitor này chứ?", - confirmClearStatisticsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ số liệu thống kê?", - importHandleDescription: "Chọn 'Skip existing' nếu bạn muốn bỏ qua mọi monitor và kênh thông báo trùng tên. 'Overwrite' sẽ ghi đè lên tất cả các monitor và kênh thông báo.", - confirmImportMsg: "Bạn có chắc chắn muốn khôi phục bản bản sao lưu này không?.", - twoFAVerifyLabel: "Vui lòng nhập mã token của bạn để xác minh rằng 2FA đang hoạt động", - tokenValidSettingsMsg: "Mã token hợp lệ! Bạn có thể lưu cài đặt 2FA bây giờ.", - confirmEnableTwoFAMsg: "Bạn chắc chắn muốn bật 2FA chứ?", - confirmDisableTwoFAMsg: "Bạn chắc chắn muốn tắt 2FA chứ?", - Settings: "Cài đặt", - Dashboard: "Dashboard", - "New Update": "Bản cập nhật mới", - Language: "Ngôn ngữ", - Appearance: "Giao diện", - Theme: "Theme", - General: "Chung", - Version: "Phiên bản", - "Check Update On GitHub": "Kiểm tra bản cập nhật mới trên GitHub", - List: "List", - Add: "Thêm", - "Add New Monitor": "Thêm mới Monitor", - "Quick Stats": "Thống kê nhanh", - Up: "Lên", - Down: "Xuống", - Pending: "Chờ xử lý", - Unknown: "Không xác định", - Pause: "Tạm dừng", - Name: "Tên", - Status: "Trạng thái", - DateTime: "Ngày tháng", - Message: "Tin nhắn", - "No important events": "Không có sự kiện quan trọng nào", - Resume: "Khôi phục", - Edit: "Sửa", - Delete: "Xoá", - Current: "Hiện tại", - Uptime: "Uptime", - "Cert Exp.": "Cert hết hạn", - days: "ngày", - day: "ngày", - "-day": "-ngày", - hour: "giờ", - "-hour": "-giờ", - Response: "Phản hồi", - Ping: "Ping", - "Monitor Type": "Kiểu monitor", - Keyword: "Từ khoá", - "Friendly Name": "Tên dễ hiểu", - URL: "URL", - Hostname: "Hostname", - Port: "Port", - "Heartbeat Interval": "Tần suất heartbeat", - Retries: "Thử lại", - "Heartbeat Retry Interval": "Tần suất thử lại của Heartbeat", - Advanced: "Nâng cao", - "Upside Down Mode": "Trạng thái đảo ngược", - "Max. Redirects": "Chuyển hướng tối đa", - "Accepted Status Codes": "Codes trạng thái chấp nhận", - Save: "Lưu", - Notifications: "Thông báo", - "Not available, please setup.": "Chưa sẵn sàng, hãy cài đặt.", - "Setup Notification": "Cài đặt thông báo", - Light: "Sáng", - Dark: "Tối", - Auto: "Tự động", - "Theme - Heartbeat Bar": "Theme - Heartbeat Bar", - Normal: "Bình thường", - Bottom: "Dưới", - None: "Không có", - Timezone: "Múi giờ", - "Search Engine Visibility": "Hiển thị với các công cụ tìm kiếm", - "Allow indexing": "Cho phép indexing", - "Discourage search engines from indexing site": "Ngăn chặn các công cụ tìm kiếm indexing trang", - "Change Password": "Thay đổi mật khẩu", - "Current Password": "Mật khẩu hiện tại", - "New Password": "Mật khẩu mới", - "Repeat New Password": "Lặp lại mật khẩu mới", - "Update Password": "Cập nhật mật khẩu", - "Disable Auth": "Tắt xác minh", - "Enable Auth": "Bật xác minh", - Logout: "Đăng xuất", - Leave: "Rời", - "I understand, please disable": "Tôi hiểu, làm ơn hãy tắt!", - Confirm: "Xác nhận", - Yes: "Có", - No: "Không", - Username: "Tài khoản", - Password: "Mật khẩu", - "Remember me": "Lưu phiên đăng nhập", - Login: "Đăng nhập", - "No Monitors, please": "Không có monitor nào", - "add one": "Thêm mới", - "Notification Type": "Kiểu thông báo", - Email: "Email", - Test: "Thử", - "Certificate Info": "Thông tin Certificate", - "Resolver Server": "Máy chủ Resolver", - "Resource Record Type": "Loại bản ghi", - "Last Result": "Kết quả cuối cùng", - "Create your admin account": "Tạo tài khoản quản trị", - "Repeat Password": "Lặp lại mật khẩu", - "Import Backup": "Khôi phục bản sao lưu", - "Export Backup": "Xuất bản sao lưu", - Export: "Xuất", - Import: "Khôi phục", - respTime: "Thời gian phản hồi (ms)", - notAvailableShort: "N/A", - "Default enabled": "Mặc định bật", - "Apply on all existing monitors": "Áp dụng cho tất cả monitor đang có", - Create: "Tạo", - "Clear Data": "Xoá dữ liệu", - Events: "Sự kiện", - Heartbeats: "Heartbeats", - "Auto Get": "Tự động lấy", - backupDescription: "Bạn có thể sao lưu tất cả các màn hình và tất cả các thông báo vào một file JSON.", - backupDescription2: "PS: Không bao gồm dữ liệu lịch sử các sự kiện.", - backupDescription3: "Hãy lưu giữ file này cẩn thận vì trong file đó chứa cả các mã token thông báo.", - alertNoFile: "Hãy chọn file để khôi phục.", - alertWrongFileType: "Hãy chọn file JSON.", - "Clear all statistics": "Xoá tất cả thống kê", - "Skip existing": "Skip existing", - Overwrite: "Ghi đè", - Options: "Tuỳ chọn", - "Keep both": "Giữ lại cả hai", - "Verify Token": "Xác minh Token", - "Setup 2FA": "Cài đặt 2FA", - "Enable 2FA": "Bật 2FA", - "Disable 2FA": "Tắt 2FA", - "2FA Settings": "Cài đặt 2FA", - "Two Factor Authentication": "Xác thực hai yếu tố", - Active: "Hoạt động", - Inactive: "Ngừng hoạt động", - Token: "Token", - "Show URI": "Hiển thị URI", - Tags: "Tags", - "Add New below or Select...": "Thêm mới ở dưới hoặc Chọn...", - "Tag with this name already exist.": "Tag với tên đã tồn tại.", - "Tag with this value already exist.": "Tag với value đã tồn tại.", - color: "Màu sắc", - "value (optional)": "Value (tuỳ chọn)", - Gray: "Xám", - Red: "Đỏ", - Orange: "Cam", - Green: "Xanh lá", - Blue: "Xanh da trời", - Indigo: "Chàm", - Purple: "Tím", - Pink: "Hồng", - "Search...": "Tìm kiếm...", - "Avg. Ping": "Ping Trung bình", - "Avg. Response": "Phản hồi trung bình", - "Entry Page": "Entry Page", - statusPageNothing: "Không có gì, hãy thêm nhóm monitor hoặc monitor.", - "No Services": "Không có dịch vụ", - "All Systems Operational": "Tất cả các hệ thống hoạt động", - "Partially Degraded Service": "Dịch vụ xuống cấp một phần", - "Degraded Service": "Degraded Service", - "Add Group": "Thêm nhóm", - "Add a monitor": "Thêm monitor", - "Edit Status Page": "Sửa trang trạng thái", - "Go to Dashboard": "Đi tới Dashboard", - "Status Page": "Trang trạng thái", - // Start notification form - defaultNotificationName: "My {notification} Alerts ({number})", - here: "tại đây", - "Required": "Bắt buộc", - "telegram": "Telegram", - "Bot Token": "Bot Token", - "You can get a token from": "Bạn có thể lấy mã token từ", - "Chat ID": "Chat ID", - supportTelegramChatID: "Hỗ trợ chat trực tiếp / Nhóm / Kênh Chat ID", - wayToGetTelegramChatID: "Bạn có thể lấy chat id của mình bằng cách gửi tin nhắn tới bot và truy cập url này để xem chat_id:", - "YOUR BOT TOKEN HERE": "MÃ BOT TOKEN CỦA BẠN", - chatIDNotFound: "Không tìm thấy Chat ID, vui lòng gửi tin nhắn cho bot này trước", - "webhook": "Webhook", - "Post URL": "URL đăng", - "Content Type": "Loại nội dung", - webhookJsonDesc: "{0} phù hợp với bất kỳ máy chủ http hiện đại nào như express.js", - webhookFormDataDesc: "{multipart} phù hợp với PHP, bạn chỉ cần phân tích cú pháp json bằng {decodeFunction}", - "smtp": "Email (SMTP)", - secureOptionNone: "None / STARTTLS (25, 587)", - secureOptionTLS: "TLS (465)", - "Ignore TLS Error": "Bỏ qua lỗi TLS", - "From Email": "Từ Email", - "To Email": "Tới Email", - smtpCC: "CC", - smtpBCC: "BCC", - "discord": "Discord", - "Discord Webhook URL": "Discord Webhook URL", - wayToGetDiscordURL: "Để lấy Discord, hãy vào: Server Settings -> Integrations -> Create Webhook", - "Bot Display Name": "Tên hiển thị của Bot", - "Prefix Custom Message": "Tiền tố tin nhắn tuỳ chọn", - "Hello @everyone is...": "Xin chào {'@'} mọi người đang...", - "teams": "Microsoft Teams", - "Webhook URL": "Webhook URL", - wayToGetTeamsURL: "Bạn có thể học cách tạo webhook url {0}.", - "signal": "Signal", - "Number": "Số", - "Recipients": "Người nhận", - needSignalAPI: "Bạn cần một tín hiệu client với REST API.", - wayToCheckSignalURL: "Bạn có thể kiểm tra url này để xem cách thiết lập:", - signalImportant: "QUAN TRỌNG: Bạn không thể kết hợp các nhóm và số trong người nhận!", - "gotify": "Gotify", - "Application Token": "Mã Token ứng dụng", - "Server URL": "URL máy chủ", - "Priority": "Mức ưu tiên", - "slack": "Slack", - "Icon Emoji": "Icon Emoji", - "Channel Name": "Tên Channel", - "Uptime Kuma URL": "Uptime Kuma URL", - aboutWebhooks: "Thông tin thêm về webhook trên: {0}", - aboutChannelName: "Nhập tên kênh trên {0} trường Channel Name nếu bạn muốn bỏ qua kênh webhook. vd: #other-channel", - aboutKumaURL: "Nếu bạn để trống trường Uptime Kuma URL, mặc định sẽ là trang Project Github.", - emojiCheatSheet: "Bảng tra cứu Emoji: {0}", - "rocket.chat": "Rocket.chat", - pushover: "Pushover", - pushy: "Pushy", - octopush: "Octopush", - promosms: "PromoSMS", - lunasea: "LunaSea", - apprise: "Thông báo (Hỗ trợ 50+ dịch vụ thông báo)", - pushbullet: "Pushbullet", - line: "Line Messenger", - mattermost: "Mattermost", - "User Key": "User Key", - "Device": "Thiết bị", - "Message Title": "Tiêu đề tin nhắn", - "Notification Sound": "Âm thanh thông báo", - "More info on:": "Thông tin chi tiết tại: {0}", - pushoverDesc1: "Mức ưu tiên khẩn cấp (2) có thời gian chờ mặc định là 30 giây giữa các lần thử lại và sẽ hết hạn sau 1 giờ.", - pushoverDesc2: "Nếu bạn muốn gửi thông báo đến các thiết bị khác nhau, hãy điền vào trường Thiết bị.", - "SMS Type": "SMS Type", - octopushTypePremium: "Premium (Nhanh - Khuyến nghị nên dùng cho cảnh báo)", - octopushTypeLowCost: "Giá rẻ (Chậm, thỉnh thoảng bị chặn)", - "Check octopush prices": "Kiểm tra giá octopush {0}.", - octopushPhoneNumber: "Số điện thoại (Định dạng intl, vd : +33612345678) ", - octopushSMSSender: "SMS người gửi : 3-11 ký tự chữ, số và dấu cách (a-zA-Z0-9)", - "LunaSea Device ID": "LunaSea ID thiết bị", - "Apprise URL": "Apprise URL", - "Example:": "Ví dụ: {0}", - "Read more:": "Đọc thêm: {0}", - "Status:": "Trạng thái: {0}", - "Read more": "Đọc thêm", - appriseInstalled: "Đã cài đặt Apprise.", - appriseNotInstalled: "Chưa cài đặt Apprise. {0}", - "Access Token": "Token truy cập", - "Channel access token": "Token kênh truy cập", - "Line Developers Console": "Line Developers Console", - lineDevConsoleTo: "Line Developers Console - {0}", - "Basic Settings": "Cài đặt cơ bản", - "User ID": "User ID", - "Messaging API": "Messaging API", - wayToGetLineChannelToken: "Trước tiên, hãy truy cập {0},tạo nhà cung cấp và kênh (Messaging API), sau đó bạn có thể nhận mã token truy cập kênh và id người dùng từ các mục menu được đề cập ở trên.", - "Icon URL": "Icon URL", - aboutIconURL: "Bạn có thể cung cấp liên kết đến ảnh trong \"Icon URL\" để ghi đè ảnh hồ sơ mặc định. Sẽ không được sử dụng nếu Biểu tượng cảm xúc được thiết lập.", - aboutMattermostChannelName: "Bạn có thể ghi đè kênh mặc định mà webhook đăng lên bằng cách nhập tên kênh vào trường \"Channel Name\". Điều này cần được bật trong cài đặt Mattermost webhook. Ví dụ: #other-channel", - "matrix": "Matrix", - promosmsTypeEco: "SMS ECO - rẻ nhưng chậm và thường xuyên quá tải. Chỉ dành cho người Ba Lan.", - promosmsTypeFlash: "SMS FLASH - Tin nhắn sẽ tự động hiển thị trên thiết bị của người nhận. Chỉ dành cho người Ba Lan.", - promosmsTypeFull: "SMS FULL - SMS cao cấp, Bạn có thể sử dụng Tên Người gửi (Bạn cần đăng ký tên trước). Đáng tin cậy cho các cảnh báo.", - promosmsTypeSpeed: "SMS SPEED - Ưu tiên cao nhất trong hệ thống. Rất nhanh chóng và đáng tin cậy nhưng tốn kém, (giá gấp đôi SMS FULL).", - promosmsPhoneNumber: "Số điện thoại (Bỏ qua mã vùng với người Ba Lan)", - promosmsSMSSender: "SMS Tên người gửi: Tên đã đăng ký trước hoặc tên mặc định: InfoSMS, SMS Info, MaxSMS, INFO, SMS", - "Feishu WebHookUrl": "Feishu WebHookUrl", - // End notification form -}; +export default { + languageName: "Vietnamese", + checkEverySecond: "Kiểm tra mỗi {0} giây.", + retryCheckEverySecond: "Thử lại mỗi {0} giây.", + retriesDescription: "Số lần thử lại tối đa trước khi dịch vụ được đánh dấu là down và gửi thông báo.", + ignoreTLSError: "Bỏ qua lỗi TLS/SSL với các web HTTPS.", + upsideDownModeDescription: "Trạng thái đảo ngược, nếu dịch vụ có thể truy cập được nghĩa là DOWN.", + maxRedirectDescription: "Số lần chuyển hướng (redirect) tối đa. Đặt thành 0 để tắt chuyển hướng", + acceptedStatusCodesDescription: "Chọn mã code trạng thái được coi là phản hồi thành công.", + passwordNotMatchMsg: "Mật khẩu nhập lại không khớp.", + notificationDescription: "Vui lòng chỉ định một kênh thông báo.", + keywordDescription: "Từ khoá tìm kiếm phản hồi ở dạng html hoặc JSON, có phân biệt chữ HOA - thường", + pauseDashboardHome: "Tạm dừng", + deleteMonitorMsg: "Bạn chắc chắn muốn xóa monitor này chứ?", + deleteNotificationMsg: "Bạn có chắc chắn muốn xóa kênh thông báo này cho tất cả monitor?", + resoverserverDescription: "Cloudflare là máy chủ mặc định, bạn có thể thay đổi bất cứ lúc nào.", + rrtypeDescription: "Hãy chọn RR-Type mà bạn muốn giám sát", + pauseMonitorMsg: "Bạn chắc chắn muốn tạm dừng chứ?", + enableDefaultNotificationDescription: "Bật làm mặc định cho mọi monitor mới về sau. Bạn vẫn có thể tắt thông báo riêng cho từng monitor.", + clearEventsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ sự kiện cho monitor này chứ?", + clearHeartbeatsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ heartbeats cho monitor này chứ?", + confirmClearStatisticsMsg: "Bạn chắc chắn muốn xoá TẤT CẢ số liệu thống kê?", + importHandleDescription: "Chọn 'Skip existing' nếu bạn muốn bỏ qua mọi monitor và kênh thông báo trùng tên. 'Overwrite' sẽ ghi đè lên tất cả các monitor và kênh thông báo.", + confirmImportMsg: "Bạn có chắc chắn muốn khôi phục bản bản sao lưu này không?.", + twoFAVerifyLabel: "Vui lòng nhập mã token của bạn để xác minh rằng 2FA đang hoạt động", + tokenValidSettingsMsg: "Mã token hợp lệ! Bạn có thể lưu cài đặt 2FA bây giờ.", + confirmEnableTwoFAMsg: "Bạn chắc chắn muốn bật 2FA chứ?", + confirmDisableTwoFAMsg: "Bạn chắc chắn muốn tắt 2FA chứ?", + Settings: "Cài đặt", + Dashboard: "Dashboard", + "New Update": "Bản cập nhật mới", + Language: "Ngôn ngữ", + Appearance: "Giao diện", + Theme: "Theme", + General: "Chung", + Version: "Phiên bản", + "Check Update On GitHub": "Kiểm tra bản cập nhật mới trên GitHub", + List: "List", + Add: "Thêm", + "Add New Monitor": "Thêm mới Monitor", + "Quick Stats": "Thống kê nhanh", + Up: "Lên", + Down: "Xuống", + Pending: "Chờ xử lý", + Unknown: "Không xác định", + Pause: "Tạm dừng", + Name: "Tên", + Status: "Trạng thái", + DateTime: "Ngày tháng", + Message: "Tin nhắn", + "No important events": "Không có sự kiện quan trọng nào", + Resume: "Khôi phục", + Edit: "Sửa", + Delete: "Xoá", + Current: "Hiện tại", + Uptime: "Uptime", + "Cert Exp.": "Cert hết hạn", + days: "ngày", + day: "ngày", + "-day": "-ngày", + hour: "giờ", + "-hour": "-giờ", + Response: "Phản hồi", + Ping: "Ping", + "Monitor Type": "Kiểu monitor", + Keyword: "Từ khoá", + "Friendly Name": "Tên dễ hiểu", + URL: "URL", + Hostname: "Hostname", + Port: "Port", + "Heartbeat Interval": "Tần suất heartbeat", + Retries: "Thử lại", + "Heartbeat Retry Interval": "Tần suất thử lại của Heartbeat", + Advanced: "Nâng cao", + "Upside Down Mode": "Trạng thái đảo ngược", + "Max. Redirects": "Chuyển hướng tối đa", + "Accepted Status Codes": "Codes trạng thái chấp nhận", + Save: "Lưu", + Notifications: "Thông báo", + "Not available, please setup.": "Chưa sẵn sàng, hãy cài đặt.", + "Setup Notification": "Cài đặt thông báo", + Light: "Sáng", + Dark: "Tối", + Auto: "Tự động", + "Theme - Heartbeat Bar": "Theme - Heartbeat Bar", + Normal: "Bình thường", + Bottom: "Dưới", + None: "Không có", + Timezone: "Múi giờ", + "Search Engine Visibility": "Hiển thị với các công cụ tìm kiếm", + "Allow indexing": "Cho phép indexing", + "Discourage search engines from indexing site": "Ngăn chặn các công cụ tìm kiếm indexing trang", + "Change Password": "Thay đổi mật khẩu", + "Current Password": "Mật khẩu hiện tại", + "New Password": "Mật khẩu mới", + "Repeat New Password": "Lặp lại mật khẩu mới", + "Update Password": "Cập nhật mật khẩu", + "Disable Auth": "Tắt xác minh", + "Enable Auth": "Bật xác minh", + Logout: "Đăng xuất", + Leave: "Rời", + "I understand, please disable": "Tôi hiểu, làm ơn hãy tắt!", + Confirm: "Xác nhận", + Yes: "Có", + No: "Không", + Username: "Tài khoản", + Password: "Mật khẩu", + "Remember me": "Lưu phiên đăng nhập", + Login: "Đăng nhập", + "No Monitors, please": "Không có monitor nào", + "add one": "Thêm mới", + "Notification Type": "Kiểu thông báo", + Email: "Email", + Test: "Thử", + "Certificate Info": "Thông tin Certificate", + "Resolver Server": "Máy chủ Resolver", + "Resource Record Type": "Loại bản ghi", + "Last Result": "Kết quả cuối cùng", + "Create your admin account": "Tạo tài khoản quản trị", + "Repeat Password": "Lặp lại mật khẩu", + "Import Backup": "Khôi phục bản sao lưu", + "Export Backup": "Xuất bản sao lưu", + Export: "Xuất", + Import: "Khôi phục", + respTime: "Thời gian phản hồi (ms)", + notAvailableShort: "N/A", + "Default enabled": "Mặc định bật", + "Apply on all existing monitors": "Áp dụng cho tất cả monitor đang có", + Create: "Tạo", + "Clear Data": "Xoá dữ liệu", + Events: "Sự kiện", + Heartbeats: "Heartbeats", + "Auto Get": "Tự động lấy", + backupDescription: "Bạn có thể sao lưu tất cả các màn hình và tất cả các thông báo vào một file JSON.", + backupDescription2: "PS: Không bao gồm dữ liệu lịch sử các sự kiện.", + backupDescription3: "Hãy lưu giữ file này cẩn thận vì trong file đó chứa cả các mã token thông báo.", + alertNoFile: "Hãy chọn file để khôi phục.", + alertWrongFileType: "Hãy chọn file JSON.", + "Clear all statistics": "Xoá tất cả thống kê", + "Skip existing": "Skip existing", + Overwrite: "Ghi đè", + Options: "Tuỳ chọn", + "Keep both": "Giữ lại cả hai", + "Verify Token": "Xác minh Token", + "Setup 2FA": "Cài đặt 2FA", + "Enable 2FA": "Bật 2FA", + "Disable 2FA": "Tắt 2FA", + "2FA Settings": "Cài đặt 2FA", + "Two Factor Authentication": "Xác thực hai yếu tố", + Active: "Hoạt động", + Inactive: "Ngừng hoạt động", + Token: "Token", + "Show URI": "Hiển thị URI", + Tags: "Tags", + "Add New below or Select...": "Thêm mới ở dưới hoặc Chọn...", + "Tag with this name already exist.": "Tag với tên đã tồn tại.", + "Tag with this value already exist.": "Tag với value đã tồn tại.", + color: "Màu sắc", + "value (optional)": "Value (tuỳ chọn)", + Gray: "Xám", + Red: "Đỏ", + Orange: "Cam", + Green: "Xanh lá", + Blue: "Xanh da trời", + Indigo: "Chàm", + Purple: "Tím", + Pink: "Hồng", + "Search...": "Tìm kiếm...", + "Avg. Ping": "Ping Trung bình", + "Avg. Response": "Phản hồi trung bình", + "Entry Page": "Entry Page", + statusPageNothing: "Không có gì, hãy thêm nhóm monitor hoặc monitor.", + "No Services": "Không có dịch vụ", + "All Systems Operational": "Tất cả các hệ thống hoạt động", + "Partially Degraded Service": "Dịch vụ xuống cấp một phần", + "Degraded Service": "Degraded Service", + "Add Group": "Thêm nhóm", + "Add a monitor": "Thêm monitor", + "Edit Status Page": "Sửa trang trạng thái", + "Go to Dashboard": "Đi tới Dashboard", + "Status Page": "Trang trạng thái", + defaultNotificationName: "My {notification} Alerts ({number})", + here: "tại đây", + Required: "Bắt buộc", + telegram: "Telegram", + "Bot Token": "Bot Token", + "You can get a token from": "Bạn có thể lấy mã token từ", + "Chat ID": "Chat ID", + supportTelegramChatID: "Hỗ trợ chat trực tiếp / Nhóm / Kênh Chat ID", + wayToGetTelegramChatID: "Bạn có thể lấy chat id của mình bằng cách gửi tin nhắn tới bot và truy cập url này để xem chat_id:", + "YOUR BOT TOKEN HERE": "MÃ BOT TOKEN CỦA BẠN", + chatIDNotFound: "Không tìm thấy Chat ID, vui lòng gửi tin nhắn cho bot này trước", + webhook: "Webhook", + "Post URL": "URL đăng", + "Content Type": "Loại nội dung", + webhookJsonDesc: "{0} phù hợp với bất kỳ máy chủ http hiện đại nào như express.js", + webhookFormDataDesc: "{multipart} phù hợp với PHP, bạn chỉ cần phân tích cú pháp json bằng {decodeFunction}", + smtp: "Email (SMTP)", + secureOptionNone: "None / STARTTLS (25, 587)", + secureOptionTLS: "TLS (465)", + "Ignore TLS Error": "Bỏ qua lỗi TLS", + "From Email": "Từ Email", + "To Email": "Tới Email", + smtpCC: "CC", + smtpBCC: "BCC", + discord: "Discord", + "Discord Webhook URL": "Discord Webhook URL", + wayToGetDiscordURL: "Để lấy Discord, hãy vào: Server Settings -> Integrations -> Create Webhook", + "Bot Display Name": "Tên hiển thị của Bot", + "Prefix Custom Message": "Tiền tố tin nhắn tuỳ chọn", + "Hello @everyone is...": "Xin chào {'@'} mọi người đang...", + teams: "Microsoft Teams", + "Webhook URL": "Webhook URL", + wayToGetTeamsURL: "Bạn có thể học cách tạo webhook url {0}.", + signal: "Signal", + Number: "Số", + Recipients: "Người nhận", + needSignalAPI: "Bạn cần một tín hiệu client với REST API.", + wayToCheckSignalURL: "Bạn có thể kiểm tra url này để xem cách thiết lập:", + signalImportant: "QUAN TRỌNG: Bạn không thể kết hợp các nhóm và số trong người nhận!", + gotify: "Gotify", + "Application Token": "Mã Token ứng dụng", + "Server URL": "URL máy chủ", + Priority: "Mức ưu tiên", + slack: "Slack", + "Icon Emoji": "Icon Emoji", + "Channel Name": "Tên Channel", + "Uptime Kuma URL": "Uptime Kuma URL", + aboutWebhooks: "Thông tin thêm về webhook trên: {0}", + aboutChannelName: "Nhập tên kênh trên {0} trường Channel Name nếu bạn muốn bỏ qua kênh webhook. vd: #other-channel", + aboutKumaURL: "Nếu bạn để trống trường Uptime Kuma URL, mặc định sẽ là trang Project Github.", + emojiCheatSheet: "Bảng tra cứu Emoji: {0}", + "rocket.chat": "Rocket.chat", + pushover: "Pushover", + pushy: "Pushy", + octopush: "Octopush", + promosms: "PromoSMS", + lunasea: "LunaSea", + apprise: "Thông báo (Hỗ trợ 50+ dịch vụ thông báo)", + pushbullet: "Pushbullet", + line: "Line Messenger", + mattermost: "Mattermost", + "User Key": "User Key", + Device: "Thiết bị", + "Message Title": "Tiêu đề tin nhắn", + "Notification Sound": "Âm thanh thông báo", + "More info on:": "Thông tin chi tiết tại: {0}", + pushoverDesc1: "Mức ưu tiên khẩn cấp (2) có thời gian chờ mặc định là 30 giây giữa các lần thử lại và sẽ hết hạn sau 1 giờ.", + pushoverDesc2: "Nếu bạn muốn gửi thông báo đến các thiết bị khác nhau, hãy điền vào trường Thiết bị.", + "SMS Type": "SMS Type", + octopushTypePremium: "Premium (Nhanh - Khuyến nghị nên dùng cho cảnh báo)", + octopushTypeLowCost: "Giá rẻ (Chậm, thỉnh thoảng bị chặn)", + "Check octopush prices": "Kiểm tra giá octopush {0}.", + octopushPhoneNumber: "Số điện thoại (Định dạng intl, vd : +33612345678) ", + octopushSMSSender: "SMS người gửi : 3-11 ký tự chữ, số và dấu cách (a-zA-Z0-9)", + "LunaSea Device ID": "LunaSea ID thiết bị", + "Apprise URL": "Apprise URL", + "Example:": "Ví dụ: {0}", + "Read more:": "Đọc thêm: {0}", + "Status:": "Trạng thái: {0}", + "Read more": "Đọc thêm", + appriseInstalled: "Đã cài đặt Apprise.", + appriseNotInstalled: "Chưa cài đặt Apprise. {0}", + "Access Token": "Token truy cập", + "Channel access token": "Token kênh truy cập", + "Line Developers Console": "Line Developers Console", + lineDevConsoleTo: "Line Developers Console - {0}", + "Basic Settings": "Cài đặt cơ bản", + "User ID": "User ID", + "Messaging API": "Messaging API", + wayToGetLineChannelToken: "Trước tiên, hãy truy cập {0},tạo nhà cung cấp và kênh (Messaging API), sau đó bạn có thể nhận mã token truy cập kênh và id người dùng từ các mục menu được đề cập ở trên.", + "Icon URL": "Icon URL", + aboutIconURL: "Bạn có thể cung cấp liên kết đến ảnh trong \"Icon URL\" để ghi đè ảnh hồ sơ mặc định. Sẽ không được sử dụng nếu Biểu tượng cảm xúc được thiết lập.", + aboutMattermostChannelName: "Bạn có thể ghi đè kênh mặc định mà webhook đăng lên bằng cách nhập tên kênh vào trường \"Channel Name\". Điều này cần được bật trong cài đặt Mattermost webhook. Ví dụ: #other-channel", + matrix: "Matrix", + promosmsTypeEco: "SMS ECO - rẻ nhưng chậm và thường xuyên quá tải. Chỉ dành cho người Ba Lan.", + promosmsTypeFlash: "SMS FLASH - Tin nhắn sẽ tự động hiển thị trên thiết bị của người nhận. Chỉ dành cho người Ba Lan.", + promosmsTypeFull: "SMS FULL - SMS cao cấp, Bạn có thể sử dụng Tên Người gửi (Bạn cần đăng ký tên trước). Đáng tin cậy cho các cảnh báo.", + promosmsTypeSpeed: "SMS SPEED - Ưu tiên cao nhất trong hệ thống. Rất nhanh chóng và đáng tin cậy nhưng tốn kém, (giá gấp đôi SMS FULL).", + promosmsPhoneNumber: "Số điện thoại (Bỏ qua mã vùng với người Ba Lan)", + promosmsSMSSender: "SMS Tên người gửi: Tên đã đăng ký trước hoặc tên mặc định: InfoSMS, SMS Info, MaxSMS, INFO, SMS", + "Feishu WebHookUrl": "Feishu WebHookUrl", +}; diff --git a/src/languages/zh-CN.js b/src/languages/zh-CN.js index a5db29027..8bbd0dcdd 100644 --- a/src/languages/zh-CN.js +++ b/src/languages/zh-CN.js @@ -65,7 +65,7 @@ export default { "Max. Redirects": "重定向次数", "Accepted Status Codes": "有效状态码", "Push URL": "推送链接", - needPushEvery: "你需要每 {0} 秒调用一次。", + needPushEvery: "你需要每 {0} 秒调用一次", pushOptionalParams: "可选参数:{0}", Save: "保存", Notifications: "消息通知", diff --git a/src/mixins/socket.js b/src/mixins/socket.js index d7ac8bcb9..679794496 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -328,6 +328,10 @@ export default { clearStatistics(callback) { socket.emit("clearStatistics", callback); }, + + getMonitorBeats(monitorID, period, callback) { + socket.emit("getMonitorBeats", monitorID, period, callback); + } }, computed: { diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index a763a4240..65c3dad6e 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -340,11 +340,17 @@ export default { }, bodyPlaceholder() { - return "{\n\t\"id\": 124357,\n\t\"username\": \"admin\",\n\t\"password\": \"myAdminPassword\"\n}"; + return `Example: +{ + "key": "value" +}`; }, headersPlaceholder() { - return "{\n\t\"Authorization\": \"Bearer abc123\",\n\t\"Content-Type\": \"application/json\"\n}"; + return `Example: +{ + "HeaderName": "HeaderValue" +}`; } }, diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index dc0198531..c3df9cd11 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -112,7 +112,7 @@ <div class="input-group mb-3"> <input id="primaryBaseURL" v-model="settings.primaryBaseURL" class="form-control" name="primaryBaseURL" placeholder="https://" pattern="https?://.+"> - <button class="btn btn-outline-primary" type="button" @click="autoGetPrimaryBaseURL">Auto Get</button> + <button class="btn btn-outline-primary" type="button" @click="autoGetPrimaryBaseURL">{{ $t("Auto Get") }}</button> </div> <div class="form-text"> @@ -149,6 +149,7 @@ <!-- Change Password --> <template v-if="! settings.disableAuth"> <h2 class="mt-5 mb-2">{{ $t("Change Password") }}</h2> + <p>{{ $t("Current User") }}: <strong>{{ this.username }}</strong></p> <form class="mb-3" @submit.prevent="savePassword"> <div class="mb-3"> <label for="current-password" class="form-label">{{ $t("Current Password") }}</label> @@ -231,13 +232,15 @@ {{ importAlert }} </div> + <!-- Advanced --> <h2 class="mt-5 mb-2">{{ $t("Advanced") }}</h2> <div class="mb-3"> <button v-if="settings.disableAuth" class="btn btn-outline-primary me-2 mb-2" @click="enableAuth">{{ $t("Enable Auth") }}</button> <button v-if="! settings.disableAuth" class="btn btn-primary me-2 mb-2" @click="confirmDisableAuth">{{ $t("Disable Auth") }}</button> <button v-if="! settings.disableAuth" class="btn btn-danger me-2 mb-2" @click="$root.logout">{{ $t("Logout") }}</button> - <button class="btn btn-outline-danger me-1 mb-1" @click="confirmClearStatistics">{{ $t("Clear all statistics") }}</button> + <button class="btn btn-outline-danger me-2 mb-2" @click="confirmClearStatistics">{{ $t("Clear all statistics") }}</button> + <button class="btn btn-info me-2 mb-2" @click="shrinkDatabase">{{ $t("Shrink Database") }} ({{ databaseSizeDisplay }})</button> </div> </template> </div> @@ -413,11 +416,13 @@ import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; import NotificationDialog from "../components/NotificationDialog.vue"; import TwoFADialog from "../components/TwoFADialog.vue"; +import jwt_decode from "jwt-decode"; dayjs.extend(utc); dayjs.extend(timezone); import { timezoneList, setPageLocale } from "../util-frontend"; import { useToast } from "vue-toastification"; +import { debug } from "../util.ts"; const toast = useToast(); @@ -427,6 +432,7 @@ export default { TwoFADialog, Confirm, }, + data() { return { timezoneList: timezoneList(), @@ -445,8 +451,16 @@ export default { importAlert: null, importHandle: "skip", processing: false, + databaseSize: 0, }; }, + + computed: { + databaseSizeDisplay() { + return Math.round(this.databaseSize / 1024 / 1024 * 10) / 10 + " MB"; + } + }, + watch: { "password.repeatNewPassword"() { this.invalidPassword = false; @@ -459,7 +473,9 @@ export default { }, mounted() { + this.loadUsername(); this.loadSettings(); + this.loadDatabaseSize(); }, methods: { @@ -484,6 +500,12 @@ export default { } }, + loadUsername() { + const jwtToken = this.$root.storage().token; + const jwtPayload = jwt_decode(jwtToken); + this.username = jwtPayload.username; + }, + loadSettings() { this.$root.getSocket().emit("getSettings", (res) => { this.settings = res.data; @@ -592,7 +614,33 @@ export default { autoGetPrimaryBaseURL() { this.settings.primaryBaseURL = location.protocol + "//" + location.host; + }, + + shrinkDatabase() { + this.$root.getSocket().emit("shrinkDatabase", (res) => { + if (res.ok) { + this.loadDatabaseSize(); + toast.success("Done"); + } else { + debug(res); + } + }); + }, + + loadDatabaseSize() { + debug("load database size"); + this.$root.getSocket().emit("getDatabaseSize", (res) => { + + if (res.ok) { + this.databaseSize = res.size; + debug("database size: " + res.size); + } else { + debug(res); + } + + }); } + }, }; </script> diff --git a/src/util-frontend.js b/src/util-frontend.js index 0b33bfd39..9094dda43 100644 --- a/src/util-frontend.js +++ b/src/util-frontend.js @@ -51,7 +51,7 @@ export function timezoneList() { } export function setPageLocale() { - const html = document.documentElement + const html = document.documentElement html.setAttribute('lang', currentLocale() ) html.setAttribute('dir', localeDirection() ) - } \ No newline at end of file +}