From 9ad8e5f56a6e544fca4c13086556ed7db73c3775 Mon Sep 17 00:00:00 2001
From: Andreas Brett <github@abrett.de>
Date: Fri, 22 Oct 2021 13:05:52 +0200
Subject: [PATCH 01/62] show logged in user

---
 server/server.js       | 21 +++++++++++++++++++++
 src/languages/de-DE.js |  1 +
 src/languages/en.js    |  1 +
 src/pages/Settings.vue |  8 ++++++++
 4 files changed, 31 insertions(+)

diff --git a/server/server.js b/server/server.js
index c4d18869..9b670b76 100644
--- a/server/server.js
+++ b/server/server.js
@@ -865,6 +865,27 @@ exports.entryPage = "dashboard";
             }
         });
 
+        socket.on("getUsername", async (callback) => {
+            try {
+                checkLogin(socket);
+
+                let user = await R.findOne("user", " id = ? AND active = 1 ", [
+                    socket.userID,
+                ]);
+
+                callback({
+                    ok: true,
+                    data: user.username,
+                });
+
+            } catch (e) {
+                callback({
+                    ok: false,
+                    msg: e.message,
+                });
+            }
+        });
+
         socket.on("getSettings", async (callback) => {
             try {
                 checkLogin(socket);
diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js
index 5e69899d..0e47701e 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -197,4 +197,5 @@ export default {
     pushbullet: "Pushbullet",
     line: "Line Messenger",
     mattermost: "Mattermost",
+    "Current User": "Aktueller Benutzer",
 };
diff --git a/src/languages/en.js b/src/languages/en.js
index 4542d72b..bb8d9635 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -305,4 +305,5 @@ export default {
     "One record": "One record",
     "Showing {from} to {to} of {count} records": "Showing {from} to {to} of {count} records",
     steamApiKeyDescription: "For monitoring a Steam Gameserver you need a steam Web-API key. You can register your api key here: ",
+    "Current User": "Current User",
 };
diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue
index dc019853..29209810 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -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>
@@ -459,6 +460,7 @@ export default {
     },
 
     mounted() {
+        this.loadUsername();
         this.loadSettings();
     },
 
@@ -484,6 +486,12 @@ export default {
             }
         },
 
+        loadUsername() {
+            this.$root.getSocket().emit("getUsername", (res) => {
+                this.username = res.data;
+            });
+        },
+
         loadSettings() {
             this.$root.getSocket().emit("getSettings", (res) => {
                 this.settings = res.data;

From 93c231b4d9803794f821595e5caf2c6af60b1539 Mon Sep 17 00:00:00 2001
From: Andreas Brett <andreasbrett@users.noreply.github.com>
Date: Sat, 23 Oct 2021 01:52:02 +0200
Subject: [PATCH 02/62] Update server/server.js

Co-authored-by: Adam Stachowicz <saibamenppl@gmail.com>
---
 server/server.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/server/server.js b/server/server.js
index 9b670b76..cf78ab8b 100644
--- a/server/server.js
+++ b/server/server.js
@@ -877,7 +877,6 @@ exports.entryPage = "dashboard";
                     ok: true,
                     data: user.username,
                 });
-
             } catch (e) {
                 callback({
                     ok: false,

From abdf1ae90a1f25afc3fb6bed99f7c661048b02e6 Mon Sep 17 00:00:00 2001
From: Andreas Brett <andreasbrett@users.noreply.github.com>
Date: Sat, 23 Oct 2021 01:53:31 +0200
Subject: [PATCH 03/62] Update en.js

---
 src/languages/en.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/languages/en.js b/src/languages/en.js
index 1c287030..b4a03a05 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -305,6 +305,6 @@ export default {
     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 Gameserver you need a steam Web-API key. You can register your api key here: ",
+    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",
 };

From 85e2b36424d7c67b56efe97ce6eb4b3fd13068b2 Mon Sep 17 00:00:00 2001
From: Andreas Brett <andreasbrett@users.noreply.github.com>
Date: Sat, 23 Oct 2021 01:54:07 +0200
Subject: [PATCH 04/62] Update en.js

---
 src/languages/en.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/languages/en.js b/src/languages/en.js
index b4a03a05..f5cdcdb6 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -305,6 +305,6 @@ export default {
     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: ",
+    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",
 };

From 4becb97a5d6341ee6d3b864f21719191bd72b484 Mon Sep 17 00:00:00 2001
From: Andreas Brett <andreasbrett@users.noreply.github.com>
Date: Sat, 23 Oct 2021 01:54:36 +0200
Subject: [PATCH 05/62] Update en.js

---
 src/languages/en.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/languages/en.js b/src/languages/en.js
index f5cdcdb6..1c848ff0 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -305,6 +305,6 @@ export default {
     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: ",
+    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",
 };

From b5eb17ed9335167019ca6073386440c961772418 Mon Sep 17 00:00:00 2001
From: kry008 <pkrzysaaaa@gmail.com>
Date: Sat, 23 Oct 2021 15:07:24 +0200
Subject: [PATCH 06/62] Update pl.js

---
 src/languages/pl.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/languages/pl.js b/src/languages/pl.js
index 2861ed0f..d2dbc36e 100644
--- a/src/languages/pl.js
+++ b/src/languages/pl.js
@@ -271,8 +271,8 @@ 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",
+    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.",

From c9549c0de2b90dfc824963ad0620d6ffd3ef528d Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Sat, 23 Oct 2021 22:14:05 +0800
Subject: [PATCH 07/62] change body and header placeholders, less misleading.

---
 src/pages/EditMonitor.vue | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue
index a763a424..65c3dad6 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"
+}`;
         }
 
     },

From ce852dfa022057587b5182cf8b0cfb93695a9dd8 Mon Sep 17 00:00:00 2001
From: Lakr Aream <master@233owo.com>
Date: Sun, 24 Oct 2021 00:20:24 +0800
Subject: [PATCH 08/62] Support for Bark (APN) notifications

Update bark.js
---
 server/notification-providers/bark.js | 89 +++++++++++++++++++++++++++
 server/notification.js                |  2 +
 src/components/notifications/Bark.vue | 15 +++++
 src/components/notifications/index.js |  4 +-
 4 files changed, 109 insertions(+), 1 deletion(-)
 create mode 100644 server/notification-providers/bark.js
 create mode 100644 src/components/notifications/Bark.vue

diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js
new file mode 100644
index 00000000..4ebe978a
--- /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.js b/server/notification.js
index 658216f9..57453c4a 100644
--- a/server/notification.js
+++ b/server/notification.js
@@ -21,6 +21,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 {
 
@@ -54,6 +55,7 @@ class Notification {
             new SMTP(),
             new Telegram(),
             new Webhook(),
+            new Bark(),
         ];
 
         for (let item of list) {
diff --git a/src/components/notifications/Bark.vue b/src/components/notifications/Bark.vue
new file mode 100644
index 00000000..014450de
--- /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/index.js b/src/components/notifications/index.js
index 96ee2824..2d8c9c09 100644
--- a/src/components/notifications/index.js
+++ b/src/components/notifications/index.js
@@ -20,6 +20,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.
@@ -48,7 +49,8 @@ const NotificationFormList = {
     "line": Line,
     "mattermost": Mattermost,
     "matrix": Matrix,
-    "DingDing": DingDing
+    "DingDing": DingDing,
+    "Bark": Bark
 }
 
 export default NotificationFormList

From b83c59e308c1f97e5c3d305d5f7e96d0f7b6f2c4 Mon Sep 17 00:00:00 2001
From: Nelson Chan <chakflying@hotmail.com>
Date: Mon, 18 Oct 2021 19:00:39 +0800
Subject: [PATCH 09/62] WIP: Add options for chart period

Fix: Fix callback, add toast on error

Fix: Improve styling

Fix: Restore default chart behavior

Fix: Replace 1h with 3h

draft only
---
 server/client.js             | 37 ++++++++++++++------
 server/server.js             | 19 ++++++++++
 src/components/PingChart.vue | 67 ++++++++++++++++++++++++++++++++----
 src/mixins/socket.js         |  4 +++
 4 files changed, 111 insertions(+), 16 deletions(-)

diff --git a/server/client.js b/server/client.js
index c7b3bc16..951ffd8a 100644
--- a/server/client.js
+++ b/server/client.js
@@ -31,19 +31,36 @@ async function sendNotificationList(socket) {
  * @param toUser  True = send to all browsers with the same user id, False = send to the current browser only
  * @param overwrite Overwrite client-side's heartbeat list
  */
-async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
+async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false, period = null) {
     const timeLogger = new TimeLogger();
 
-    let list = await R.getAll(`
-        SELECT * FROM heartbeat
-        WHERE monitor_id = ?
-        ORDER BY time DESC
-        LIMIT 100
-    `, [
-        monitorID,
-    ]);
+    let result;
 
-    let result = list.reverse();
+    if (period) {
+        let list = await R.getAll(`
+            SELECT * FROM heartbeat
+            WHERE monitor_id = ? AND
+            time > DATETIME('now', '-' || ? || ' hours')
+            ORDER BY time ASC
+        `, [
+            monitorID,
+            period,
+        ]);
+
+        result = list;
+
+    } else {
+        let list = await R.getAll(`
+            SELECT * FROM heartbeat
+            WHERE monitor_id = ?
+            ORDER BY time DESC
+            LIMIT 100
+        `, [
+            monitorID,
+        ]);
+
+        result = list.reverse();
+    }
 
     if (toUser) {
         io.to(socket.userID).emit("heartbeatList", monitorID, result, overwrite);
diff --git a/server/server.js b/server/server.js
index 3084cad2..4209b45c 100644
--- a/server/server.js
+++ b/server/server.js
@@ -644,6 +644,25 @@ exports.entryPage = "dashboard";
             }
         });
 
+        socket.on("getMonitorBeats", async (monitorID, period, callback) => {
+            try {
+                checkLogin(socket);
+
+                console.log(`Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`);
+
+                await sendHeartbeatList(socket, monitorID, true, true, period);
+
+                callback({
+                    ok: true
+                });
+            } catch (e) {
+                callback({
+                    ok: false,
+                    msg: e.message,
+                });
+            }
+        });
+
         // Start or Resume the monitor
         socket.on("resumeMonitor", async (monitorID, callback) => {
             try {
diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue
index 0baa9881..4818bba2 100644
--- a/src/components/PingChart.vue
+++ b/src/components/PingChart.vue
@@ -1,5 +1,18 @@
 <template>
-    <LineChart :chart-data="chartData" :options="chartOptions" />
+    <div>
+        <div class="period-options">
+            {{ $t("show") }}: <select id="chart-period-select" v-model="chartPeriodHrs" class="form-select form-select-sm ms-1">
+                <option value="0">{{ $t("recent") }}</option>
+                <option value="3">3h</option>
+                <option value="6">6h</option>
+                <option value="24">24h</option>
+                <option value="168">1w</option>
+            </select>
+        </div>
+        <div class="chart-wrapper">
+            <LineChart :chart-data="chartData" :options="chartOptions" />
+        </div>
+    </div>
 </template>
 
 <script>
@@ -9,8 +22,11 @@ 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";
+
 dayjs.extend(utc);
 dayjs.extend(timezone);
+const toast = useToast();
 
 Chart.register(LineController, BarController, LineElement, PointElement, TimeScale, BarElement, LinearScale, Tooltip, Filler);
 
@@ -25,7 +41,12 @@ export default {
     data() {
         return {
             // Configurable filtering on top of the returned data
-            chartPeriodHrs: 6,
+            chartPeriodHrs: 0,
+
+            // Just Draft:
+            // A heartbeatList for 3h, 6h, 24h, 1w
+            // Set it to null, switch back to realtime (last 100 beats)
+            heartbeatList: null
         };
     },
     computed: {
@@ -117,7 +138,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,7 +146,7 @@ export default {
                         display: false,
                     },
                 },
-            }
+            };
         },
         chartData() {
             let pingData = [];  // Ping Data for Line Chart, y-axis contains ping time
@@ -133,7 +154,7 @@ export default {
             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")))
+                        (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({
@@ -143,7 +164,7 @@ export default {
                         downData.push({
                             x,
                             y: beat.status === 0 ? 1 : 0,
-                        })
+                        });
                     });
             }
             return {
@@ -172,5 +193,39 @@ export default {
             };
         },
     },
+    watch: {
+        chartPeriodHrs: function (newPeriod) {
+            if (newPeriod == "0") {
+                newPeriod = null;
+            }
+            this.$root.getMonitorBeats(this.monitorId, newPeriod, (res) => {
+                if (!res.ok) {
+                    toast.error(res.msg);
+                }
+            });
+        }
+    },
 };
 </script>
+
+<style lang="scss" scoped>
+@import "../assets/vars.scss";
+
+.form-select {
+    width: unset;
+    display: inline-flex;
+}
+
+.period-options {
+    padding: 0.3em 1.5em;
+    margin-bottom: -1.5em;
+    float: right;
+    position: relative;
+    z-index: 10;
+    font-size: 0.8em;
+}
+
+.chart-wrapper {
+    margin-bottom: 1.5em;
+}
+</style>
diff --git a/src/mixins/socket.js b/src/mixins/socket.js
index d7ac8bcb..67979449 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: {

From 2f7b60f5e50b6c2c370739e376580d74b172f39e Mon Sep 17 00:00:00 2001
From: Nelson Chan <chakflying@hotmail.com>
Date: Fri, 22 Oct 2021 18:38:41 +0800
Subject: [PATCH 10/62] Feat: Use separate storage for custom chart period

Fix: Fix import error
---
 server/client.js             | 37 ++++++---------------
 server/server.js             | 17 ++++++++--
 src/components/PingChart.vue | 64 +++++++++++++++++++++++-------------
 3 files changed, 67 insertions(+), 51 deletions(-)

diff --git a/server/client.js b/server/client.js
index 951ffd8a..c7b3bc16 100644
--- a/server/client.js
+++ b/server/client.js
@@ -31,36 +31,19 @@ async function sendNotificationList(socket) {
  * @param toUser  True = send to all browsers with the same user id, False = send to the current browser only
  * @param overwrite Overwrite client-side's heartbeat list
  */
-async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false, period = null) {
+async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) {
     const timeLogger = new TimeLogger();
 
-    let result;
+    let list = await R.getAll(`
+        SELECT * FROM heartbeat
+        WHERE monitor_id = ?
+        ORDER BY time DESC
+        LIMIT 100
+    `, [
+        monitorID,
+    ]);
 
-    if (period) {
-        let list = await R.getAll(`
-            SELECT * FROM heartbeat
-            WHERE monitor_id = ? AND
-            time > DATETIME('now', '-' || ? || ' hours')
-            ORDER BY time ASC
-        `, [
-            monitorID,
-            period,
-        ]);
-
-        result = list;
-
-    } else {
-        let list = await R.getAll(`
-            SELECT * FROM heartbeat
-            WHERE monitor_id = ?
-            ORDER BY time DESC
-            LIMIT 100
-        `, [
-            monitorID,
-        ]);
-
-        result = list.reverse();
-    }
+    let result = list.reverse();
 
     if (toUser) {
         io.to(socket.userID).emit("heartbeatList", monitorID, result, overwrite);
diff --git a/server/server.js b/server/server.js
index 4209b45c..49e867da 100644
--- a/server/server.js
+++ b/server/server.js
@@ -650,10 +650,23 @@ exports.entryPage = "dashboard";
 
                 console.log(`Get Monitor Beats: ${monitorID} User ID: ${socket.userID}`);
 
-                await sendHeartbeatList(socket, monitorID, true, true, period);
+                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
+                    ok: true,
+                    data: list,
                 });
             } catch (e) {
                 callback({
diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue
index 4818bba2..0c76721c 100644
--- a/src/components/PingChart.vue
+++ b/src/components/PingChart.vue
@@ -15,7 +15,7 @@
     </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";
@@ -23,6 +23,7 @@ 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);
@@ -151,22 +152,28 @@ export default {
         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(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 === 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: [
                     {
@@ -197,14 +204,27 @@ export default {
         chartPeriodHrs: function (newPeriod) {
             if (newPeriod == "0") {
                 newPeriod = null;
+                this.heartbeatList = null;
+            } else {
+                this.$root.getMonitorBeats(this.monitorId, newPeriod, (res) => {
+                    if (!res.ok) {
+                        toast.error(res.msg);
+                    } else {
+                        this.heartbeatList = res.data;
+                    }
+                });
             }
-            this.$root.getMonitorBeats(this.monitorId, newPeriod, (res) => {
-                if (!res.ok) {
-                    toast.error(res.msg);
-                }
-            });
         }
     },
+    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) {
+                this.heartbeatList.push(heartbeatList.at(-1));
+            }
+        }, { deep: true });
+    }
 };
 </script>
 
@@ -217,7 +237,7 @@ export default {
 }
 
 .period-options {
-    padding: 0.3em 1.5em;
+    padding: 0.3em 2.2em;
     margin-bottom: -1.5em;
     float: right;
     position: relative;

From 445674aacb0c58ca5eb96dc2c7c033a4d70c8670 Mon Sep 17 00:00:00 2001
From: Nelson Chan <chakflying@hotmail.com>
Date: Fri, 22 Oct 2021 18:44:11 +0800
Subject: [PATCH 11/62] Chore: Improve code formatting & comments

---
 src/components/PingChart.vue | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue
index 0c76721c..cd5e239c 100644
--- a/src/components/PingChart.vue
+++ b/src/components/PingChart.vue
@@ -1,7 +1,12 @@
 <template>
     <div>
         <div class="period-options">
-            {{ $t("show") }}: <select id="chart-period-select" v-model="chartPeriodHrs" class="form-select form-select-sm ms-1">
+            {{ $t("show") }}:
+            <select
+                id="chart-period-select"
+                v-model="chartPeriodHrs"
+                class="form-select form-select-sm ms-1"
+            >
                 <option value="0">{{ $t("recent") }}</option>
                 <option value="3">3h</option>
                 <option value="6">6h</option>
@@ -44,9 +49,8 @@ export default {
             // Configurable filtering on top of the returned data
             chartPeriodHrs: 0,
 
-            // Just Draft:
             // A heartbeatList for 3h, 6h, 24h, 1w
-            // Set it to null, switch back to realtime (last 100 beats)
+            // Uses the $root.heartbeatList when value is null
             heartbeatList: null
         };
     },
@@ -161,7 +165,10 @@ export default {
                 .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")))
+                    (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({
@@ -201,6 +208,7 @@ export default {
         },
     },
     watch: {
+        // Update chart data when the selected chart period changes
         chartPeriodHrs: function (newPeriod) {
             if (newPeriod == "0") {
                 newPeriod = null;
@@ -219,11 +227,14 @@ export default {
     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) {
-                this.heartbeatList.push(heartbeatList.at(-1));
-            }
-        }, { deep: true });
+        this.$watch(() => this.$root.heartbeatList[this.monitorId],
+            (heartbeatList) => {
+                if (this.chartPeriodHrs != 0) {
+                    this.heartbeatList.push(heartbeatList.at(-1));
+                }
+            },
+            { deep: true }
+        );
     }
 };
 </script>

From e4be28a9e748086d12b50799f151b35a7e09e091 Mon Sep 17 00:00:00 2001
From: Nelson Chan <chakflying@hotmail.com>
Date: Fri, 22 Oct 2021 19:07:11 +0800
Subject: [PATCH 12/62] Fix: Validate beat time before appending

---
 src/components/PingChart.vue | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue
index cd5e239c..adbca1b6 100644
--- a/src/components/PingChart.vue
+++ b/src/components/PingChart.vue
@@ -230,7 +230,10 @@ export default {
         this.$watch(() => this.$root.heartbeatList[this.monitorId],
             (heartbeatList) => {
                 if (this.chartPeriodHrs != 0) {
-                    this.heartbeatList.push(heartbeatList.at(-1));
+                    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 }

From 665bae08061d19a08877504fefca9917bcb3335f Mon Sep 17 00:00:00 2001
From: Nelson Chan <chakflying@hotmail.com>
Date: Sun, 24 Oct 2021 01:26:56 +0800
Subject: [PATCH 13/62] UI: Simplify dropdown design

---
 src/components/PingChart.vue | 80 ++++++++++++++++++++++++++++--------
 1 file changed, 64 insertions(+), 16 deletions(-)

diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue
index adbca1b6..7f4043c0 100644
--- a/src/components/PingChart.vue
+++ b/src/components/PingChart.vue
@@ -1,18 +1,14 @@
 <template>
     <div>
         <div class="period-options">
-            {{ $t("show") }}:
-            <select
-                id="chart-period-select"
-                v-model="chartPeriodHrs"
-                class="form-select form-select-sm ms-1"
-            >
-                <option value="0">{{ $t("recent") }}</option>
-                <option value="3">3h</option>
-                <option value="6">6h</option>
-                <option value="24">24h</option>
-                <option value="168">1w</option>
-            </select>
+            <button type="button" class="btn btn-light dropdown-toggle btn-period-toggle" data-bs-toggle="dropdown" aria-expanded="false">
+                {{ chartPeriodOptions[chartPeriodHrs] }}&nbsp;
+            </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">
             <LineChart :chart-data="chartData" :options="chartOptions" />
@@ -49,6 +45,14 @@ export default {
             // Configurable filtering on top of the returned data
             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
@@ -251,15 +255,59 @@ export default {
 }
 
 .period-options {
-    padding: 0.3em 2.2em;
-    margin-bottom: -1.5em;
+    padding: 0.1em 1.0em;
+    margin-bottom: -2em;
     float: right;
     position: relative;
     z-index: 10;
-    font-size: 0.8em;
+
+    .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: 1.5em;
+    margin-bottom: 0.5em;
 }
 </style>

From 9a9fca67d50a0d192d3cf784354aacd5938e12cb Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sat, 23 Oct 2021 22:58:35 -0400
Subject: [PATCH 14/62] Migrate Bug Report to Github Issue Forms

---
 .github/ISSUE_TEMPLATE/bug_report.md   |  42 ----------
 .github/ISSUE_TEMPLATE/bug_report.yaml | 105 +++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 42 deletions(-)
 delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
 create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml

diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 069ed6cc..00000000
--- 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 00000000..acffc517
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -0,0 +1,105 @@
+name: "🐛 Bug Report"
+description: "Submit a bug report to help us improve"
+title: "🐛 Bug Report: "
+labels: [bug]
+body:
+  - type: markdown
+    attributes:
+      value: |
+        Thanks for taking the time to fill out this bug report!
+  - 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: dropdown
+    id: uptime-kuma-version
+    attributes:
+      label: "🐻 Uptime-Kuma version"
+      description: "What version of Uptime-Kuma are you running?"
+      options:
+        - latest
+        - nightly
+        - Version 1.9.x
+        - Version 1.8.x
+        - Version 1.7.x
+        - Different version
+    validations:
+      required: true
+  - type: dropdown
+    id: operating-system
+    attributes:
+      label: "💻 Operating System"
+      description: "What OS is your server / device running on?"
+      options:
+        - Linux
+        - MacOS
+        - Windows
+    validations:
+      required: true
+  - type: dropdown
+    id: browser-vendor
+    attributes:
+      label: "🌐 Browser"
+      description: "What browser are you running on?"
+      options:
+        - Firefox
+        - Chrome
+        - Edge
+        - Safari
+        - Other
+    validations:
+      required: true
+  - type: checkboxes
+    id: uses-docker
+    attributes:
+      label: "🐋 Docker"
+      options:
+        - label: "Currently running in Docker?"
+          required: false
+    validations:
+      required: true
+  - type: dropdown
+    id: nodejs-version
+    attributes:
+      label: "🟩 NodeJS Version"
+      description: "What version of NodeJS are you running?"
+      options:
+        - 14
+        - 16
+        - 17
+    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
+  - 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

From bdebbf8e40b7fdd4724c0f50a66da263430e779f Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sun, 24 Oct 2021 00:40:06 -0400
Subject: [PATCH 15/62] Add Support for Issue Forms

---
 .github/ISSUE_TEMPLATE/ask-for-help.md      | 21 ------
 .github/ISSUE_TEMPLATE/ask-for-help.yaml    | 79 +++++++++++++++++++++
 .github/ISSUE_TEMPLATE/bug_report.yaml      |  4 +-
 .github/ISSUE_TEMPLATE/feature_request.md   | 22 ------
 .github/ISSUE_TEMPLATE/feature_request.yaml | 45 ++++++++++++
 5 files changed, 127 insertions(+), 44 deletions(-)
 delete mode 100644 .github/ISSUE_TEMPLATE/ask-for-help.md
 create mode 100644 .github/ISSUE_TEMPLATE/ask-for-help.yaml
 delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
 create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yaml

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.md b/.github/ISSUE_TEMPLATE/ask-for-help.md
deleted file mode 100644
index 3031e077..00000000
--- 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 00000000..41361e27
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -0,0 +1,79 @@
+name: "❓ Ask for help"
+description: "Submit any question related to Uptime Kuma"
+title: "❓ Ask for help: "
+labels: [help]
+body:
+  - type: textarea
+    id: steps-to-reproduce
+    validations:
+      required: true
+    attributes:
+      label: "👟 Reproduction steps"
+      description: "Please walk us through it step by step."
+      placeholder: "Describe what are you asking for..."
+  - type: dropdown
+    id: uptime-kuma-version
+    attributes:
+      label: "🐻 Uptime-Kuma version"
+      description: "What version of Uptime-Kuma are you running?"
+      options:
+        - latest
+        - nightly
+        - Version 1.9.x
+        - Version 1.8.x
+        - Version 1.7.x
+        - Different version
+    validations:
+      required: true
+  - type: dropdown
+    id: operating-system
+    attributes:
+      label: "💻 Operating System"
+      description: "What OS is your server / device running on?"
+      options:
+        - Linux
+        - MacOS
+        - Windows
+    validations:
+      required: true
+  - type: dropdown
+    id: browser-vendor
+    attributes:
+      label: "🌐 Browser"
+      description: "What browser are you running on?"
+      options:
+        - Firefox
+        - Chrome
+        - Edge
+        - Safari
+        - Other
+    validations:
+      required: true
+  - type: checkboxes
+    id: uses-docker
+    attributes:
+      label: "🐋 Docker"
+      options:
+        - label: "Currently running in Docker?"
+          required: false
+    validations:
+      required: true
+  - type: dropdown
+    id: nodejs-version
+    attributes:
+      label: "🟩 NodeJS Version"
+      description: "If running in the host, Which version of NodeJS are you running?"
+      options:
+        - 14
+        - 16
+        - 17
+    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
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index acffc517..8d14c906 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -82,7 +82,7 @@ body:
     id: nodejs-version
     attributes:
       label: "🟩 NodeJS Version"
-      description: "What version of NodeJS are you running?"
+      description: "If running in the host, Which version of NodeJS are you running?"
       options:
         - 14
         - 16
@@ -95,6 +95,8 @@ body:
       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:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 4794cc24..00000000
--- 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 00000000..93c3fdfe
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yaml
@@ -0,0 +1,45 @@
+name: 🚀 Feature
+description: "Submit a proposal for a new feature"
+title: "🚀 Feature: "
+labels: [enhancement]
+body:
+  - 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
\ No newline at end of file

From 95342ec0066d2d3afeb7dc0ecc28e2bdfbf2a721 Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sun, 24 Oct 2021 00:41:51 -0400
Subject: [PATCH 16/62] Update label for ask for help

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index 41361e27..46f06d44 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -8,7 +8,7 @@ body:
     validations:
       required: true
     attributes:
-      label: "👟 Reproduction steps"
+      label: "📝 Describe your problem"
       description: "Please walk us through it step by step."
       placeholder: "Describe what are you asking for..."
   - type: dropdown

From c489058a571d8d6f440cffec696fc92be34f03ac Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sun, 24 Oct 2021 00:46:10 -0400
Subject: [PATCH 17/62] Update labels for each form

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml    | 2 +-
 .github/ISSUE_TEMPLATE/bug_report.yaml      | 2 +-
 .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index 46f06d44..0c77c262 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -1,6 +1,6 @@
 name: "❓ Ask for help"
 description: "Submit any question related to Uptime Kuma"
-title: "❓ Ask for help: "
+title: "[Help]: "
 labels: [help]
 body:
   - type: textarea
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 8d14c906..53de8003 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -1,6 +1,6 @@
 name: "🐛 Bug Report"
 description: "Submit a bug report to help us improve"
-title: "🐛 Bug Report: "
+title: "[Bug]: "
 labels: [bug]
 body:
   - type: markdown
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml
index 93c3fdfe..11260a28 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yaml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yaml
@@ -1,6 +1,6 @@
 name: 🚀 Feature
 description: "Submit a proposal for a new feature"
-title: "🚀 Feature: "
+title: "[Feature]: "
 labels: [enhancement]
 body:
   - type: textarea

From 40a1ebecc5120c5c7795ea9b20ea3d6ba5139c93 Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sun, 24 Oct 2021 00:51:47 -0400
Subject: [PATCH 18/62] Update feature_request.yaml

---
 .github/ISSUE_TEMPLATE/feature_request.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml
index 11260a28..5d23e3ec 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yaml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yaml
@@ -1,4 +1,4 @@
-name: 🚀 Feature
+name: 🚀 Feature Request
 description: "Submit a proposal for a new feature"
 title: "[Feature]: "
 labels: [enhancement]
@@ -42,4 +42,4 @@ body:
       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
\ No newline at end of file
+          required: true

From 89c64f4ea2464fd0fd669adf1b852ed66ecd32a5 Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <saibamenppl@gmail.com>
Date: Sun, 24 Oct 2021 11:16:29 +0200
Subject: [PATCH 19/62] Create PULL_REQUEST_TEMPLATE.md

From https://github.com/Harsha200105/DesktopAssistant/pull/51
---
 .github/PULL_REQUEST_TEMPLATE.md | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 .github/PULL_REQUEST_TEMPLATE.md

diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..58bd3030
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,21 @@
+# Description
+
+Fixes #(issue)
+
+## Type of change
+
+- [ ] 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)
+- [ ] This change requires a documentation update
+
+
+# Checklist:
+
+- [ ] My code follows the style guidelines of this project
+- [ ] I have performed a self-review of my own code
+- [ ] I have commented my code, particularly in hard-to-understand areas
+- [ ] My changes generate no new warnings
+
+# Screenshots (if any)

From ab5ddae2eeb96f85cd852a22604153740019cddc Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <saibamenppl@gmail.com>
Date: Sun, 24 Oct 2021 11:18:07 +0200
Subject: [PATCH 20/62] Delete double new line

---
 .github/PULL_REQUEST_TEMPLATE.md | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 58bd3030..5c326682 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -10,7 +10,6 @@ Fixes #(issue)
 - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
 - [ ] This change requires a documentation update
 
-
 # Checklist:
 
 - [ ] My code follows the style guidelines of this project

From 8fe5e4e605873d83656374fd8f0a5b669aab6f53 Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <saibamenppl@gmail.com>
Date: Sun, 24 Oct 2021 11:19:42 +0200
Subject: [PATCH 21/62] Fix lint

---
 .github/PULL_REQUEST_TEMPLATE.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 5c326682..d9c2cec5 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -10,11 +10,11 @@ Fixes #(issue)
 - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
 - [ ] This change requires a documentation update
 
-# Checklist:
+## Checklist
 
 - [ ] My code follows the style guidelines of this project
 - [ ] I have performed a self-review of my own code
 - [ ] I have commented my code, particularly in hard-to-understand areas
 - [ ] My changes generate no new warnings
 
-# Screenshots (if any)
+## Screenshots (if any)

From 65158cb06bfade0459720e73e6c1d486da376e1b Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <saibamenppl@gmail.com>
Date: Sun, 24 Oct 2021 12:21:59 +0200
Subject: [PATCH 22/62] Update PULL_REQUEST_TEMPLATE.md

Changes after Code Review
---
 .github/PULL_REQUEST_TEMPLATE.md | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index d9c2cec5..be2caa09 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -8,13 +8,16 @@ Fixes #(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
 - [ ] This change requires a documentation update
 
 ## Checklist
 
 - [ ] My code follows the style guidelines of this project
-- [ ] I have performed a self-review of my own code
+- [ ] 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
 
 ## Screenshots (if any)

From b50b3900484d1b255e966053fb1cc3438a7def1c Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sun, 24 Oct 2021 10:04:56 -0400
Subject: [PATCH 23/62] Changes based on PR requests

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml    | 30 ++++++++++-----------
 .github/ISSUE_TEMPLATE/bug_report.yaml      | 30 ++++++++++-----------
 .github/ISSUE_TEMPLATE/feature_request.yaml | 16 ++++++++++-
 3 files changed, 43 insertions(+), 33 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index 0c77c262..834ba3d4 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -1,6 +1,6 @@
 name: "❓ Ask for help"
 description: "Submit any question related to Uptime Kuma"
-title: "[Help]: "
+title: "[Help]: <title>"
 labels: [help]
 body:
   - type: textarea
@@ -11,25 +11,19 @@ body:
       label: "📝 Describe your problem"
       description: "Please walk us through it step by step."
       placeholder: "Describe what are you asking for..."
-  - type: dropdown
+  - type: input
     id: uptime-kuma-version
     attributes:
       label: "🐻 Uptime-Kuma version"
       description: "What version of Uptime-Kuma are you running?"
-      options:
-        - latest
-        - nightly
-        - Version 1.9.x
-        - Version 1.8.x
-        - Version 1.7.x
-        - Different version
     validations:
       required: true
   - type: dropdown
     id: operating-system
     attributes:
       label: "💻 Operating System"
-      description: "What OS is your server / device running on?"
+      description: "What OS is your server/device running on?"
+      multiple: true
       options:
         - Linux
         - MacOS
@@ -41,6 +35,7 @@ body:
     attributes:
       label: "🌐 Browser"
       description: "What browser are you running on?"
+      multiple: true
       options:
         - Firefox
         - Chrome
@@ -58,15 +53,11 @@ body:
           required: false
     validations:
       required: true
-  - type: dropdown
+  - type: input
     id: nodejs-version
     attributes:
       label: "🟩 NodeJS Version"
-      description: "If running in the host, Which version of NodeJS are you running?"
-      options:
-        - 14
-        - 16
-        - 17
+      description: "If running in the host, which version of NodeJS are you running?"
     validations:
       required: false
   - type: checkboxes
@@ -77,3 +68,10 @@ body:
       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.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 53de8003..bffa1315 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -1,6 +1,6 @@
 name: "🐛 Bug Report"
 description: "Submit a bug report to help us improve"
-title: "[Bug]: "
+title: "[Bug]: <title>"
 labels: [bug]
 body:
   - type: markdown
@@ -31,25 +31,19 @@ body:
       label: "👎 Actual Behavior"
       description: "What actually happen?"
       placeholder: "..."
-  - type: dropdown
+  - type: input
     id: uptime-kuma-version
     attributes:
       label: "🐻 Uptime-Kuma version"
       description: "What version of Uptime-Kuma are you running?"
-      options:
-        - latest
-        - nightly
-        - Version 1.9.x
-        - Version 1.8.x
-        - Version 1.7.x
-        - Different version
     validations:
       required: true
   - type: dropdown
     id: operating-system
     attributes:
       label: "💻 Operating System"
-      description: "What OS is your server / device running on?"
+      description: "What OS is your server/device running on?"
+      multiple: true
       options:
         - Linux
         - MacOS
@@ -61,6 +55,7 @@ body:
     attributes:
       label: "🌐 Browser"
       description: "What browser are you running on?"
+      multiple: true
       options:
         - Firefox
         - Chrome
@@ -78,15 +73,11 @@ body:
           required: false
     validations:
       required: true
-  - type: dropdown
+  - type: input
     id: nodejs-version
     attributes:
       label: "🟩 NodeJS Version"
-      description: "If running in the host, Which version of NodeJS are you running?"
-      options:
-        - 14
-        - 16
-        - 17
+      description: "If running in the host, which version of NodeJS are you running?"
     validations:
       required: false
   - type: textarea
@@ -105,3 +96,10 @@ body:
       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.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml
index 5d23e3ec..ef76ff28 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yaml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yaml
@@ -1,8 +1,22 @@
 name: 🚀 Feature Request
 description: "Submit a proposal for a new feature"
-title: "[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:

From c7e1267779724bf34c6e3b3d5ab86489bac6aea4 Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sun, 24 Oct 2021 10:12:17 -0400
Subject: [PATCH 24/62] More syntax changes. Change What to Which

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml | 6 +++---
 .github/ISSUE_TEMPLATE/bug_report.yaml   | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index 834ba3d4..bde3ad8d 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -15,14 +15,14 @@ body:
     id: uptime-kuma-version
     attributes:
       label: "🐻 Uptime-Kuma version"
-      description: "What version of Uptime-Kuma are you running?"
+      description: "Which version of Uptime-Kuma are you running?"
     validations:
       required: true
   - type: dropdown
     id: operating-system
     attributes:
       label: "💻 Operating System"
-      description: "What OS is your server/device running on?"
+      description: "Which OS is your server/device running on?"
       multiple: true
       options:
         - Linux
@@ -34,7 +34,7 @@ body:
     id: browser-vendor
     attributes:
       label: "🌐 Browser"
-      description: "What browser are you running on?"
+      description: "Which browser are you running on?"
       multiple: true
       options:
         - Firefox
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index bffa1315..05591ff3 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -35,14 +35,14 @@ body:
     id: uptime-kuma-version
     attributes:
       label: "🐻 Uptime-Kuma version"
-      description: "What version of Uptime-Kuma are you running?"
+      description: "Which version of Uptime-Kuma are you running?"
     validations:
       required: true
   - type: dropdown
     id: operating-system
     attributes:
       label: "💻 Operating System"
-      description: "What OS is your server/device running on?"
+      description: "Which OS is your server/device running on?"
       multiple: true
       options:
         - Linux
@@ -54,7 +54,7 @@ body:
     id: browser-vendor
     attributes:
       label: "🌐 Browser"
-      description: "What browser are you running on?"
+      description: "Which browser are you running on?"
       multiple: true
       options:
         - Firefox

From 7c63cbfd84852a63086ac3bd7489d5fa9ff05cdc Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Sun, 24 Oct 2021 22:50:33 +0800
Subject: [PATCH 25/62] add node.js 17 to auto test

---
 .github/workflows/auto-test.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/auto-test.yml b/.github/workflows/auto-test.yml
index c59a61b9..e01c02ce 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:

From d82f305f6efd551f844d68ab8fb30a403705c580 Mon Sep 17 00:00:00 2001
From: Ponkhy <github@myon.lu>
Date: Sun, 24 Oct 2021 17:56:05 +0200
Subject: [PATCH 26/62] Updated german language file

---
 src/languages/de-DE.js | 107 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js
index 5e69899d..740c8852 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -197,4 +197,111 @@ 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: ",
 };

From bc68088350f475ed9f89a1b5ee496877ab28b5d8 Mon Sep 17 00:00:00 2001
From: Tarun Singh <taruninsa1@gmail.com>
Date: Sun, 24 Oct 2021 15:17:29 -0400
Subject: [PATCH 27/62] Click send sms integration for notifications

---
 server/notification-providers/clicksendsms.js |  43 ++
 server/notification.js                        |   2 +
 src/components/notifications/ClickSendSMS.vue |  35 ++
 src/components/notifications/index.js         |   2 +
 src/languages/bg-BG.js                        |   1 +
 src/languages/da-DK.js                        |   1 +
 src/languages/de-DE.js                        |   1 +
 src/languages/en.js                           |   2 +
 src/languages/es-ES.js                        |   1 +
 src/languages/et-EE.js                        |   1 +
 src/languages/fa.js                           |   1 +
 src/languages/fr-FR.js                        |   1 +
 src/languages/hu.js                           |   1 +
 src/languages/id-ID.js                        |   1 +
 src/languages/it-IT.js                        |   1 +
 src/languages/ja.js                           |   1 +
 src/languages/ko-KR.js                        |   1 +
 src/languages/nb-NO.js                        |   1 +
 src/languages/nl-NL.js                        |   3 +-
 src/languages/pl.js                           |   1 +
 src/languages/pt-BR.js                        |   1 +
 src/languages/ru-RU.js                        |   1 +
 src/languages/sr-latn.js                      |   1 +
 src/languages/sr.js                           |   1 +
 src/languages/sv-SE.js                        |   1 +
 src/languages/tr-TR.js                        |   1 +
 src/languages/vi.js                           | 571 +++++++++---------
 src/languages/zh-CN.js                        |   1 +
 src/languages/zh-HK.js                        |   1 +
 29 files changed, 394 insertions(+), 286 deletions(-)
 create mode 100644 server/notification-providers/clicksendsms.js
 create mode 100644 src/components/notifications/ClickSendSMS.vue

diff --git a/server/notification-providers/clicksendsms.js b/server/notification-providers/clicksendsms.js
new file mode 100644
index 00000000..a5075af7
--- /dev/null
+++ b/server/notification-providers/clicksendsms.js
@@ -0,0 +1,43 @@
+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, ""),
+                        // TODO: To phone number concept to be added
+                        "to": "+61411111111",
+                        "source": "uptime-kuma",
+                        "from": notification.clicksendsmsSenderName,
+                    }
+                ]
+            };
+            let resp = await axios.post("https://rest.clicksend.com/v3/sms/send", data, config);
+            if (resp.data.http_code !== 200) {
+                let error = "Something gone wrong. Api returned " + resp.data.response.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 658216f9..c7989f73 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");
@@ -45,6 +46,7 @@ class Notification {
             new Matrix(),
             new Octopush(),
             new PromoSMS(),
+            new ClickSendSMS(),
             new Pushbullet(),
             new Pushover(),
             new Pushy(),
diff --git a/src/components/notifications/ClickSendSMS.vue b/src/components/notifications/ClickSendSMS.vue
new file mode 100644
index 00000000..6e23aebe
--- /dev/null
+++ b/src/components/notifications/ClickSendSMS.vue
@@ -0,0 +1,35 @@
+<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">here</a>
+        </div>
+    </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 96ee2824..35bd5d69 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";
@@ -40,6 +41,7 @@ const NotificationFormList = {
     "pushy": Pushy,
     "octopush": Octopush,
     "promosms": PromoSMS,
+    "clicksendsms": ClickSendSMS,
     "lunasea": LunaSea,
     "Feishu": Feishu,
     "AliyunSMS": AliyunSMS,
diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js
index a7be06f1..13df5bcf 100644
--- a/src/languages/bg-BG.js
+++ b/src/languages/bg-BG.js
@@ -191,6 +191,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Поддържа 50+ услуги за инвестяване)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/da-DK.js b/src/languages/da-DK.js
index 66e7cb3d..43503fa0 100644
--- a/src/languages/da-DK.js
+++ b/src/languages/da-DK.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js
index 5e69899d..437575ce 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -192,6 +192,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Unterstützung für 50+ Benachrichtigungsdienste)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/en.js b/src/languages/en.js
index d3a69c19..cf738a14 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -241,6 +241,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
@@ -257,6 +258,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) ",
diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js
index ccd42c8f..be04194a 100644
--- a/src/languages/es-ES.js
+++ b/src/languages/es-ES.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Admite más de 50 servicios de notificación)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/et-EE.js b/src/languages/et-EE.js
index 52439f5f..05604926 100644
--- a/src/languages/et-EE.js
+++ b/src/languages/et-EE.js
@@ -192,6 +192,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (vahendab üle 65 teavitusteenust)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/fa.js b/src/languages/fa.js
index 7eed151a..f8beb8d5 100644
--- a/src/languages/fa.js
+++ b/src/languages/fa.js
@@ -200,6 +200,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/fr-FR.js b/src/languages/fr-FR.js
index 22c656b3..04c69df0 100644
--- a/src/languages/fr-FR.js
+++ b/src/languages/fr-FR.js
@@ -236,6 +236,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/hu.js b/src/languages/hu.js
index 47ac72d6..103e14b7 100644
--- a/src/languages/hu.js
+++ b/src/languages/hu.js
@@ -191,6 +191,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/id-ID.js b/src/languages/id-ID.js
index 5cb38ea6..ff66be41 100644
--- a/src/languages/id-ID.js
+++ b/src/languages/id-ID.js
@@ -236,6 +236,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Mendukung 50+ layanan notifikasi)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js
index 5ddc414f..a3719d0a 100644
--- a/src/languages/it-IT.js
+++ b/src/languages/it-IT.js
@@ -192,6 +192,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/ja.js b/src/languages/ja.js
index f96028e4..e795d12d 100644
--- a/src/languages/ja.js
+++ b/src/languages/ja.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js
index ad7b4337..29a02b27 100644
--- a/src/languages/ko-KR.js
+++ b/src/languages/ko-KR.js
@@ -235,6 +235,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (50개 이상 알림 서비스)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/nb-NO.js b/src/languages/nb-NO.js
index 50b3a534..94e19a25 100644
--- a/src/languages/nb-NO.js
+++ b/src/languages/nb-NO.js
@@ -236,6 +236,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js
index 8af03200..ee87e043 100644
--- a/src/languages/nl-NL.js
+++ b/src/languages/nl-NL.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
@@ -203,5 +204,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 2861ed0f..8c62f44e 100644
--- a/src/languages/pl.js
+++ b/src/languages/pl.js
@@ -236,6 +236,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Obsługuje 50+ usług powiadomień)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/pt-BR.js b/src/languages/pt-BR.js
index 70647fd9..69cccc96 100644
--- a/src/languages/pt-BR.js
+++ b/src/languages/pt-BR.js
@@ -192,6 +192,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/ru-RU.js b/src/languages/ru-RU.js
index bf4d3086..046c4cc7 100644
--- a/src/languages/ru-RU.js
+++ b/src/languages/ru-RU.js
@@ -197,6 +197,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Поддержка 50+ сервисов уведомлений)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/sr-latn.js b/src/languages/sr-latn.js
index 9e66aa54..4b629ccb 100644
--- a/src/languages/sr-latn.js
+++ b/src/languages/sr-latn.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/sr.js b/src/languages/sr.js
index df8e9899..346e8d4c 100644
--- a/src/languages/sr.js
+++ b/src/languages/sr.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/sv-SE.js b/src/languages/sv-SE.js
index e29d355c..7a847907 100644
--- a/src/languages/sv-SE.js
+++ b/src/languages/sv-SE.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js
index e2630603..8b84a699 100644
--- a/src/languages/tr-TR.js
+++ b/src/languages/tr-TR.js
@@ -192,6 +192,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/vi.js b/src/languages/vi.js
index c47ebe02..291e5376 100644
--- a/src/languages/vi.js
+++ b/src/languages/vi.js
@@ -1,285 +1,286 @@
-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",
+    // 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",
+    clicksendsms: "ClickSend SMS",
+    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
+};
diff --git a/src/languages/zh-CN.js b/src/languages/zh-CN.js
index a5db2902..b18d47d8 100644
--- a/src/languages/zh-CN.js
+++ b/src/languages/zh-CN.js
@@ -197,6 +197,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (支持50+种通知服务)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/zh-HK.js b/src/languages/zh-HK.js
index 7f5e2259..d4e7e7f3 100644
--- a/src/languages/zh-HK.js
+++ b/src/languages/zh-HK.js
@@ -193,6 +193,7 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
+    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (支援 50 多種通知)",
     pushbullet: "Pushbullet",

From 1239f6d1a2575f082c717a5377007f97dd9b3535 Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <adam.stachowicz@fingo.info>
Date: Sun, 24 Oct 2021 21:50:02 +0200
Subject: [PATCH 28/62] PL update + fixes

---
 src/languages/bg-BG.js |   2 +-
 src/languages/de-DE.js |   2 +-
 src/languages/en.js    |  32 ++-
 src/languages/es-ES.js |   2 +-
 src/languages/fr-FR.js |  30 +--
 src/languages/id-ID.js |  30 +--
 src/languages/nb-NO.js |  30 +--
 src/languages/nl-NL.js |   2 +-
 src/languages/pl.js    |  61 +++--
 src/languages/vi.js    | 568 ++++++++++++++++++++---------------------
 src/pages/Settings.vue |   2 +-
 11 files changed, 387 insertions(+), 374 deletions(-)

diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js
index a7be06f1..c497d6ac 100644
--- a/src/languages/bg-BG.js
+++ b/src/languages/bg-BG.js
@@ -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 740c8852..20658fec 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -297,7 +297,7 @@ export default {
     PushUrl: "Push URL",
     HeadersInvalidFormat: "Die Header ist kein gültiges JSON: ",
     BodyInvalidFormat: "Der Body ist kein gültiges JSON: ",
-    "Monitor History": "Monitor Verlauf:",
+    "Monitor History": "Monitor Verlauf",
     clearDataOlderThan: "Bewahre die Monitor-Verlaufsdaten für {0} Tage auf.",
     PasswordsDoNotMatch: "Passwörter stimmen nicht überein.",
     records: "Einträge",
diff --git a/src/languages/en.js b/src/languages/en.js
index d3a69c19..08c8b4a9 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",
@@ -247,7 +246,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}",
@@ -280,7 +279,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,14 +291,13 @@ 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",
diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js
index ccd42c8f..2f238cdc 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 22c656b3..062435d7 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 5cb38ea6..5bad2a7e 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 50b3a534..0e566a01 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 8af03200..818893af 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 d2dbc36e..7bc2747b 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}",
@@ -273,12 +272,36 @@ export default {
     "Icon URL": "Adres Ikony",
     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",
+    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ź {0} ceny:",
+    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: "records",
+    "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/vi.js b/src/languages/vi.js
index c47ebe02..0bfa3f20 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/pages/Settings.vue b/src/pages/Settings.vue
index dc019853..9762da8d 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">

From 85053f865edb1288991e801cb5b7790b183b64ad Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <adam.stachowicz@fingo.info>
Date: Sun, 24 Oct 2021 21:56:37 +0200
Subject: [PATCH 29/62] Fix typo

---
 src/languages/pl.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/languages/pl.js b/src/languages/pl.js
index 7bc2747b..3e24d422 100644
--- a/src/languages/pl.js
+++ b/src/languages/pl.js
@@ -284,7 +284,7 @@ export default {
     needPushEvery: "Powinieneś wywoływać ten URL co {0} sekund.",
     pushOptionalParams: "Parametry opcjonalne: {0}",
     emailCustomSubject: "Niestandardowy temat",
-    checkPrice: "Sprawdź {0} ceny:",
+    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)",

From fa5ba12e1496660cda7d634619c98148ff61cdf5 Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <adam.stachowicz@fingo.info>
Date: Sun, 24 Oct 2021 22:15:02 +0200
Subject: [PATCH 30/62] Missing this

---
 src/languages/pl.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/languages/pl.js b/src/languages/pl.js
index 3e24d422..9444fd34 100644
--- a/src/languages/pl.js
+++ b/src/languages/pl.js
@@ -300,7 +300,7 @@ export default {
     "Monitor History": "Historia monitorów",
     clearDataOlderThan: "Przechowuj dane dotyczące historii monitorowania {0} dni.",
     PasswordsDoNotMatch: "Hasła nie pasują.",
-    records: "records",
+    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: ",

From 9ddd2c73653a2c22e03c8dadc93b69d9c25e12f4 Mon Sep 17 00:00:00 2001
From: Andreas Brett <github@abrett.de>
Date: Mon, 25 Oct 2021 01:23:02 +0200
Subject: [PATCH 31/62] use jwt

---
 server/server.js       | 20 --------------------
 src/pages/Settings.vue |  8 +++++---
 2 files changed, 5 insertions(+), 23 deletions(-)

diff --git a/server/server.js b/server/server.js
index a2169463..11f03061 100644
--- a/server/server.js
+++ b/server/server.js
@@ -894,26 +894,6 @@ exports.entryPage = "dashboard";
             }
         });
 
-        socket.on("getUsername", async (callback) => {
-            try {
-                checkLogin(socket);
-
-                let user = await R.findOne("user", " id = ? AND active = 1 ", [
-                    socket.userID,
-                ]);
-
-                callback({
-                    ok: true,
-                    data: user.username,
-                });
-            } catch (e) {
-                callback({
-                    ok: false,
-                    msg: e.message,
-                });
-            }
-        });
-
         socket.on("getSettings", async (callback) => {
             try {
                 checkLogin(socket);
diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue
index 29209810..2ac85643 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -487,9 +487,11 @@ export default {
         },
 
         loadUsername() {
-            this.$root.getSocket().emit("getUsername", (res) => {
-                this.username = res.data;
-            });
+            const jwtToken = localStorage.getItem("token");
+            const [match, headerBase64, payloadBase64, signatureBase64] = jwtToken.match(/^(\S+)\.(\S+)\.(\S+)$/i);
+            const payload = atob(payloadBase64);
+            const oPayload = JSON.parse(payload);
+            this.username = oPayload.username;
         },
 
         loadSettings() {

From 7bc38d423140a8360f3102634856c23855f67644 Mon Sep 17 00:00:00 2001
From: Andreas Brett <github@abrett.de>
Date: Mon, 25 Oct 2021 01:33:45 +0200
Subject: [PATCH 32/62] remove unused vars

---
 src/pages/Settings.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue
index 2ac85643..f564fa2d 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -488,7 +488,7 @@ export default {
 
         loadUsername() {
             const jwtToken = localStorage.getItem("token");
-            const [match, headerBase64, payloadBase64, signatureBase64] = jwtToken.match(/^(\S+)\.(\S+)\.(\S+)$/i);
+            const [, payloadBase64] = jwtToken.match(/^\S+\.(\S+)\.\S+$/i);
             const payload = atob(payloadBase64);
             const oPayload = JSON.parse(payload);
             this.username = oPayload.username;

From 2e4c42941a01f02b203758f128d12539152687b5 Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Sun, 24 Oct 2021 21:31:10 -0400
Subject: [PATCH 33/62] Rename stale-bot to stale-bot.yml

---
 .github/workflows/{stale-bot => stale-bot.yml} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename .github/workflows/{stale-bot => stale-bot.yml} (100%)

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

From 24c645e437af2f530cfeaa8e5c40624b7407c156 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Mon, 25 Oct 2021 10:59:13 +0800
Subject: [PATCH 34/62] [empty commit] pull request for free-disk-space


From 3a43fec666783edc5575e5b25fd2ddb404c01ffe Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Mon, 25 Oct 2021 12:06:01 +0800
Subject: [PATCH 35/62] add recommend pull request guideline

---
 CONTRIBUTING.md | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1d9b37a3..c3432c4d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -29,12 +29,28 @@ 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. 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
@@ -46,6 +62,13 @@ I do not have such knowledge to test it.
 
 - Add k8s supports
 
+#### ⚠ 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 and my 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 of Uptime Kuma  
+- Drop a table or drop a column for any reason
+
 #### *️⃣ Low Priority
 
 It changed my current workflow and require further studies.
@@ -54,6 +77,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

From 3c795bebe3a66cbfc441717c158986dbef50c1dd Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Mon, 25 Oct 2021 12:06:49 +0800
Subject: [PATCH 36/62] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c3432c4d..b808aa1a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -55,6 +55,7 @@ Easy to review, no breaking change and not touching the existing code
 - Add a chart
 - Fix a bug
 - Translations
+- Add a independent new feature
 
 #### *️⃣ Requires one more reviewer
 

From e69799f613561284e6bb4a837291cc8677bcafbf Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Mon, 25 Oct 2021 12:07:44 +0800
Subject: [PATCH 37/62] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b808aa1a..e521b6c1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -63,7 +63,7 @@ I do not have such knowledge to test it.
 
 - Add k8s supports
 
-#### ⚠ Harsh Mode
+#### ⚠ 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 and my 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.
 

From a5f15f23196b048ab3d5e0197c6bff50afdc7a7d Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Mon, 25 Oct 2021 12:29:40 +0800
Subject: [PATCH 38/62] Fix #793, check dist-backup existing before delete

---
 extra/download-dist.js | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/extra/download-dist.js b/extra/download-dist.js
index 0a08b7f9..dc64166c 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);

From ba1e025353c579104d551adb05df93a2ae735508 Mon Sep 17 00:00:00 2001
From: Tarun Singh <taruninsa1@gmail.com>
Date: Mon, 25 Oct 2021 04:11:57 -0400
Subject: [PATCH 39/62] added click send to number

---
 server/notification-providers/clicksendsms.js | 7 +++----
 src/components/notifications/ClickSendSMS.vue | 7 +++++--
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/server/notification-providers/clicksendsms.js b/server/notification-providers/clicksendsms.js
index a5075af7..74e2f4c5 100644
--- a/server/notification-providers/clicksendsms.js
+++ b/server/notification-providers/clicksendsms.js
@@ -20,16 +20,15 @@ class ClickSendSMS extends NotificationProvider {
                 messages: [
                     {
                         "body": msg.replace(/[^\x00-\x7F]/g, ""),
-                        // TODO: To phone number concept to be added
-                        "to": "+61411111111",
+                        "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.http_code !== 200) {
-                let error = "Something gone wrong. Api returned " + resp.data.response.status + ".";
+            if (resp.data.data.messages[0].status !== "SUCCESS") {
+                let error = "Something gone wrong. Api returned " + resp.data.data.messages[0].status + ".";
                 this.throwGeneralAxiosError(error);
             }
 
diff --git a/src/components/notifications/ClickSendSMS.vue b/src/components/notifications/ClickSendSMS.vue
index 6e23aebe..2aed4184 100644
--- a/src/components/notifications/ClickSendSMS.vue
+++ b/src/components/notifications/ClickSendSMS.vue
@@ -12,9 +12,13 @@
     <div class="mb-3">
         <div class="form-text">
             {{ $t("checkPrice", [$t("clicksendsms")]) }}
-            <a href="https://www.clicksend.com/us/pricing" target="_blank">here</a>
+            <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>
@@ -23,7 +27,6 @@
         <div class="form-text">Leave blank to use a shared sender number.</div>
     </div>
 </template>
-
 <script>
 import HiddenInput from "../HiddenInput.vue";
 

From 9d3a4e9d1e784061f4b6aa36d7514f35de5e7eeb Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <adam.stachowicz@fingo.info>
Date: Tue, 26 Oct 2021 00:00:54 +0200
Subject: [PATCH 40/62] Remove dot from `needPushEvery`

---
 src/languages/bg-BG.js | 2 +-
 src/languages/de-DE.js | 2 +-
 src/languages/pl.js    | 2 +-
 src/languages/ru-RU.js | 2 +-
 src/languages/zh-CN.js | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js
index c497d6ac..0bb59077 100644
--- a/src/languages/bg-BG.js
+++ b/src/languages/bg-BG.js
@@ -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: "тук",
diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js
index 20658fec..11176eff 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -199,7 +199,7 @@ export default {
     mattermost: "Mattermost",
     "Primary Base URL": "Primär URL",
     "Push URL": "Push URL",
-    needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen.",
+    needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen",
     pushOptionalParams: "Optionale Parameter: {0}",
     defaultNotificationName: "Meine {notification} Alarm ({number})",
     here: "hier",
diff --git a/src/languages/pl.js b/src/languages/pl.js
index 9444fd34..b7188555 100644
--- a/src/languages/pl.js
+++ b/src/languages/pl.js
@@ -281,7 +281,7 @@ export default {
     promosmsSMSSender: "Nadawca SMS (Wcześniej zatwierdzone nazwy z panelu PromoSMS)",
     "Primary Base URL": "Główny URL",
     "Push URL": "Push URL",
-    needPushEvery: "Powinieneś wywoływać ten URL co {0} sekund.",
+    needPushEvery: "Powinieneś wywoływać ten URL co {0} sekund",
     pushOptionalParams: "Parametry opcjonalne: {0}",
     emailCustomSubject: "Niestandardowy temat",
     checkPrice: "Sprawdź ceny {0}:",
diff --git a/src/languages/ru-RU.js b/src/languages/ru-RU.js
index bf4d3086..1b0da54f 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/zh-CN.js b/src/languages/zh-CN.js
index a5db2902..8bbd0dcd 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: "消息通知",

From 6362ef6a9c6bf517b8b5acb65920008bb4256433 Mon Sep 17 00:00:00 2001
From: Tarun Singh <taruninsa1@gmail.com>
Date: Mon, 25 Oct 2021 18:30:40 -0400
Subject: [PATCH 41/62] removed other langauge translation data

---
 src/languages/bg-BG.js   | 1 -
 src/languages/da-DK.js   | 1 -
 src/languages/de-DE.js   | 1 -
 src/languages/es-ES.js   | 1 -
 src/languages/et-EE.js   | 1 -
 src/languages/fa.js      | 1 -
 src/languages/fr-FR.js   | 1 -
 src/languages/hu.js      | 1 -
 src/languages/id-ID.js   | 1 -
 src/languages/it-IT.js   | 1 -
 src/languages/ja.js      | 1 -
 src/languages/ko-KR.js   | 1 -
 src/languages/nb-NO.js   | 1 -
 src/languages/nl-NL.js   | 1 -
 src/languages/pl.js      | 1 -
 src/languages/pt-BR.js   | 1 -
 src/languages/ru-RU.js   | 1 -
 src/languages/sr-latn.js | 1 -
 src/languages/sr.js      | 1 -
 src/languages/sv-SE.js   | 1 -
 src/languages/tr-TR.js   | 1 -
 src/languages/vi.js      | 1 -
 src/languages/zh-CN.js   | 1 -
 src/languages/zh-HK.js   | 1 -
 24 files changed, 24 deletions(-)

diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js
index 13df5bcf..a7be06f1 100644
--- a/src/languages/bg-BG.js
+++ b/src/languages/bg-BG.js
@@ -191,7 +191,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Поддържа 50+ услуги за инвестяване)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/da-DK.js b/src/languages/da-DK.js
index 43503fa0..66e7cb3d 100644
--- a/src/languages/da-DK.js
+++ b/src/languages/da-DK.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js
index 79e963f5..740c8852 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -192,7 +192,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Unterstützung für 50+ Benachrichtigungsdienste)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js
index be04194a..ccd42c8f 100644
--- a/src/languages/es-ES.js
+++ b/src/languages/es-ES.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Admite más de 50 servicios de notificación)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/et-EE.js b/src/languages/et-EE.js
index 05604926..52439f5f 100644
--- a/src/languages/et-EE.js
+++ b/src/languages/et-EE.js
@@ -192,7 +192,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (vahendab üle 65 teavitusteenust)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/fa.js b/src/languages/fa.js
index f8beb8d5..7eed151a 100644
--- a/src/languages/fa.js
+++ b/src/languages/fa.js
@@ -200,7 +200,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/fr-FR.js b/src/languages/fr-FR.js
index 04c69df0..22c656b3 100644
--- a/src/languages/fr-FR.js
+++ b/src/languages/fr-FR.js
@@ -236,7 +236,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/hu.js b/src/languages/hu.js
index 103e14b7..47ac72d6 100644
--- a/src/languages/hu.js
+++ b/src/languages/hu.js
@@ -191,7 +191,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/id-ID.js b/src/languages/id-ID.js
index ff66be41..5cb38ea6 100644
--- a/src/languages/id-ID.js
+++ b/src/languages/id-ID.js
@@ -236,7 +236,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Mendukung 50+ layanan notifikasi)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js
index a3719d0a..5ddc414f 100644
--- a/src/languages/it-IT.js
+++ b/src/languages/it-IT.js
@@ -192,7 +192,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/ja.js b/src/languages/ja.js
index e795d12d..f96028e4 100644
--- a/src/languages/ja.js
+++ b/src/languages/ja.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js
index 29a02b27..ad7b4337 100644
--- a/src/languages/ko-KR.js
+++ b/src/languages/ko-KR.js
@@ -235,7 +235,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (50개 이상 알림 서비스)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/nb-NO.js b/src/languages/nb-NO.js
index 94e19a25..50b3a534 100644
--- a/src/languages/nb-NO.js
+++ b/src/languages/nb-NO.js
@@ -236,7 +236,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js
index ee87e043..818893af 100644
--- a/src/languages/nl-NL.js
+++ b/src/languages/nl-NL.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/pl.js b/src/languages/pl.js
index 2274f5ba..d2dbc36e 100644
--- a/src/languages/pl.js
+++ b/src/languages/pl.js
@@ -236,7 +236,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Obsługuje 50+ usług powiadomień)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/pt-BR.js b/src/languages/pt-BR.js
index 69cccc96..70647fd9 100644
--- a/src/languages/pt-BR.js
+++ b/src/languages/pt-BR.js
@@ -192,7 +192,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/ru-RU.js b/src/languages/ru-RU.js
index 046c4cc7..bf4d3086 100644
--- a/src/languages/ru-RU.js
+++ b/src/languages/ru-RU.js
@@ -197,7 +197,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Поддержка 50+ сервисов уведомлений)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/sr-latn.js b/src/languages/sr-latn.js
index 4b629ccb..9e66aa54 100644
--- a/src/languages/sr-latn.js
+++ b/src/languages/sr-latn.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/sr.js b/src/languages/sr.js
index 346e8d4c..df8e9899 100644
--- a/src/languages/sr.js
+++ b/src/languages/sr.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/sv-SE.js b/src/languages/sv-SE.js
index 7a847907..e29d355c 100644
--- a/src/languages/sv-SE.js
+++ b/src/languages/sv-SE.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js
index 8b84a699..e2630603 100644
--- a/src/languages/tr-TR.js
+++ b/src/languages/tr-TR.js
@@ -192,7 +192,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (Support 50+ Notification services)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/vi.js b/src/languages/vi.js
index 291e5376..2021287c 100644
--- a/src/languages/vi.js
+++ b/src/languages/vi.js
@@ -236,7 +236,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Thông báo (Hỗ trợ 50+ dịch vụ thông báo)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/zh-CN.js b/src/languages/zh-CN.js
index b18d47d8..a5db2902 100644
--- a/src/languages/zh-CN.js
+++ b/src/languages/zh-CN.js
@@ -197,7 +197,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (支持50+种通知服务)",
     pushbullet: "Pushbullet",
diff --git a/src/languages/zh-HK.js b/src/languages/zh-HK.js
index d4e7e7f3..7f5e2259 100644
--- a/src/languages/zh-HK.js
+++ b/src/languages/zh-HK.js
@@ -193,7 +193,6 @@ export default {
     pushy: "Pushy",
     octopush: "Octopush",
     promosms: "PromoSMS",
-    clicksendsms: "ClickSend SMS",
     lunasea: "LunaSea",
     apprise: "Apprise (支援 50 多種通知)",
     pushbullet: "Pushbullet",

From 7f0dda6a449e169dabfe4f03f4e9f820e31df629 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Tue, 26 Oct 2021 11:28:38 +0800
Subject: [PATCH 42/62] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e521b6c1..4cbf2423 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -40,7 +40,8 @@ If you are not sure whether I will accept your pull request, feel free to create
 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. Create a pull request: https://github.com/louislam/uptime-kuma/compare
+1. Write a proper description   
 1. Click "Change to draft"
 
 ### Pull Request Examples
@@ -65,10 +66,12 @@ I do not have such knowledge to test it.
 
 #### ⚠ 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 and my 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.
+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 of Uptime Kuma  
+- 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
 
 #### *️⃣ Low Priority
 

From f8055ed03dd82140f1de9e7af3dd165cec671aa7 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Tue, 26 Oct 2021 12:33:46 +0800
Subject: [PATCH 43/62] minor css

---
 src/components/PingChart.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue
index 7f4043c0..04c00ca8 100644
--- a/src/components/PingChart.vue
+++ b/src/components/PingChart.vue
@@ -255,8 +255,8 @@ export default {
 }
 
 .period-options {
-    padding: 0.1em 1.0em;
-    margin-bottom: -2em;
+    padding: 0.1em 1em;
+    margin-bottom: -1.2em;
     float: right;
     position: relative;
     z-index: 10;

From 78424b4f2de893de574b28a677b2d5bf55556e10 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Tue, 26 Oct 2021 12:48:21 +0800
Subject: [PATCH 44/62] add simple loading chart effect

---
 src/components/PingChart.vue | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/components/PingChart.vue b/src/components/PingChart.vue
index 04c00ca8..aa209fab 100644
--- a/src/components/PingChart.vue
+++ b/src/components/PingChart.vue
@@ -10,7 +10,7 @@
                 </li>
             </ul>
         </div>
-        <div class="chart-wrapper">
+        <div class="chart-wrapper" :class="{ loading : loading}">
             <LineChart :chart-data="chartData" :options="chartOptions" />
         </div>
     </div>
@@ -42,6 +42,9 @@ export default {
     },
     data() {
         return {
+
+            loading: false,
+
             // Configurable filtering on top of the returned data
             chartPeriodHrs: 0,
 
@@ -218,12 +221,15 @@ export default {
                 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;
                 });
             }
         }
@@ -309,5 +315,9 @@ export default {
 
 .chart-wrapper {
     margin-bottom: 0.5em;
+
+    &.loading {
+        filter: blur(10px);
+    }
 }
 </style>

From a1cda93ad5cd91af5f173d6e3d123b465018a682 Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <saibamenppl@gmail.com>
Date: Tue, 26 Oct 2021 09:46:12 +0200
Subject: [PATCH 45/62] Update PULL_REQUEST_TEMPLATE.md

See https://github.com/louislam/uptime-kuma/pull/785#issuecomment-950521657
---
 .github/PULL_REQUEST_TEMPLATE.md | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index be2caa09..937f5a10 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -4,12 +4,14 @@ Fixes #(issue)
 
 ## Type of change
 
-- [ ] 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
-- [ ] This change requires a documentation update
+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
+- This change requires a documentation update
 
 ## Checklist
 
@@ -18,6 +20,6 @@ Fixes #(issue)
 - [ ] 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
+- [ ] My code needed automated testing. I have added them (this is optional task)
 
 ## Screenshots (if any)

From 1d5c0502ab55846af362d6d58e3397752eeda99b Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <saibamenppl@gmail.com>
Date: Tue, 26 Oct 2021 09:48:17 +0200
Subject: [PATCH 46/62] Add other

---
 .github/PULL_REQUEST_TEMPLATE.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 937f5a10..fa0aa883 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -11,6 +11,7 @@ Please delete options that are not relevant.
 - 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

From 9123e9461f8b4783a23944532ce0d24e7bdd8716 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Tue, 26 Oct 2021 16:38:00 +0800
Subject: [PATCH 47/62] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4cbf2423..afdcfcbb 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -72,6 +72,8 @@ Some pull requests are required to modifiy the core. To be honest, I do not want
 - 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
 

From 3f3d8b4eb3ff205b6619cb84b72dea75cb5b12ec Mon Sep 17 00:00:00 2001
From: Andreas Brett <github@abrett.de>
Date: Tue, 26 Oct 2021 12:58:04 +0200
Subject: [PATCH 48/62] fixes

---
 src/pages/Settings.vue | 10 ++++------
 src/util-frontend.js   | 19 +++++++++++++++++--
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue
index f564fa2d..ba1e82cd 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -417,7 +417,7 @@ import TwoFADialog from "../components/TwoFADialog.vue";
 dayjs.extend(utc);
 dayjs.extend(timezone);
 
-import { timezoneList, setPageLocale } from "../util-frontend";
+import { timezoneList, setPageLocale, jwtDecrypt } from "../util-frontend";
 import { useToast } from "vue-toastification";
 
 const toast = useToast();
@@ -487,11 +487,9 @@ export default {
         },
 
         loadUsername() {
-            const jwtToken = localStorage.getItem("token");
-            const [, payloadBase64] = jwtToken.match(/^\S+\.(\S+)\.\S+$/i);
-            const payload = atob(payloadBase64);
-            const oPayload = JSON.parse(payload);
-            this.username = oPayload.username;
+            const jwtToken = this.$root.storage().token;
+            const jwtPayload = jwtDecrypt(jwtToken);
+            this.username = jwtPayload.username;
         },
 
         loadSettings() {
diff --git a/src/util-frontend.js b/src/util-frontend.js
index 0b33bfd3..2412ced1 100644
--- a/src/util-frontend.js
+++ b/src/util-frontend.js
@@ -51,7 +51,22 @@ 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
+}
+
+export function jwtDecrypt(token) {
+    const base64Url = token.split(".")[1];
+    const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
+    const jsonPayload = decodeURIComponent(
+      atob(base64)
+        .split("")
+        .map(function(c) {
+            return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
+        })
+        .join("")
+    );
+
+    return JSON.parse(jsonPayload);
+}

From 8fb8cbdaf3f8331f2c64514f8df8b510511e8992 Mon Sep 17 00:00:00 2001
From: Andreas Brett <github@abrett.de>
Date: Tue, 26 Oct 2021 13:15:31 +0200
Subject: [PATCH 49/62] use auth0/jwt-decode

---
 package-lock.json      | 11 +++++++++++
 package.json           |  1 +
 src/pages/Settings.vue |  5 +++--
 src/util-frontend.js   | 15 ---------------
 4 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 551504d7..9f412529 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 4f3d32ea..10ad4a08 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/src/pages/Settings.vue b/src/pages/Settings.vue
index ba1e82cd..93ac07a4 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -414,10 +414,11 @@ 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, jwtDecrypt } from "../util-frontend";
+import { timezoneList, setPageLocale } from "../util-frontend";
 import { useToast } from "vue-toastification";
 
 const toast = useToast();
@@ -488,7 +489,7 @@ export default {
 
         loadUsername() {
             const jwtToken = this.$root.storage().token;
-            const jwtPayload = jwtDecrypt(jwtToken);
+            const jwtPayload = jwt_decode(jwtToken);
             this.username = jwtPayload.username;
         },
 
diff --git a/src/util-frontend.js b/src/util-frontend.js
index 2412ced1..9094dda4 100644
--- a/src/util-frontend.js
+++ b/src/util-frontend.js
@@ -55,18 +55,3 @@ export function setPageLocale() {
     html.setAttribute('lang', currentLocale() )
     html.setAttribute('dir', localeDirection() )
 }
-
-export function jwtDecrypt(token) {
-    const base64Url = token.split(".")[1];
-    const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
-    const jsonPayload = decodeURIComponent(
-      atob(base64)
-        .split("")
-        .map(function(c) {
-            return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
-        })
-        .join("")
-    );
-
-    return JSON.parse(jsonPayload);
-}

From a9e319517a1b0737a5256ea6724a89b6cfb7c7b6 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Tue, 26 Oct 2021 23:02:32 +0800
Subject: [PATCH 50/62] add auto vacuum and shrink database button

---
 server/database.js                            | 12 ++++++
 server/server.js                              |  2 +
 .../database-socket-handler.js                | 37 +++++++++++++++++
 src/pages/Settings.vue                        | 41 ++++++++++++++++++-
 4 files changed, 91 insertions(+), 1 deletion(-)
 create mode 100644 server/socket-handlers/database-socket-handler.js

diff --git a/server/database.js b/server/database.js
index c9d9cc57..98494251 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/server.js b/server/server.js
index 49e867da..324ae677 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());
 
@@ -1295,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 00000000..42fdb129
--- /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/pages/Settings.vue b/src/pages/Settings.vue
index 9762da8d..e88f8605 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -231,13 +231,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>
@@ -418,6 +420,7 @@ dayjs.extend(timezone);
 
 import { timezoneList, setPageLocale } from "../util-frontend";
 import { useToast } from "vue-toastification";
+import { debug } from "../util.ts";
 
 const toast = useToast();
 
@@ -427,6 +430,7 @@ export default {
         TwoFADialog,
         Confirm,
     },
+
     data() {
         return {
             timezoneList: timezoneList(),
@@ -445,8 +449,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;
@@ -460,6 +472,7 @@ export default {
 
     mounted() {
         this.loadSettings();
+        this.loadDatabaseSize();
     },
 
     methods: {
@@ -592,7 +605,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>

From 8d984881c9761af852b6dfbf895d3d17aaa1a592 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Tue, 26 Oct 2021 23:56:14 +0800
Subject: [PATCH 51/62] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index afdcfcbb..54279857 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -210,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.git
+
+
 ## Maintainer 
 
 Check the latest issues and pull requests:
@@ -229,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
+```
+

From e0e1ab6fa6ee41bf802d21f57735ecb9cea683c5 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Wed, 27 Oct 2021 00:02:20 +0800
Subject: [PATCH 52/62] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 54279857..c9f186df 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -214,7 +214,7 @@ Please read: https://github.com/louislam/uptime-kuma/tree/master/src/languages
 
 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.git
+https://github.com/louislam/uptime-kuma-wiki
 
 
 ## Maintainer 

From f25653d778e8ea24a1bff9caeee58d904367d5ec Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Wed, 27 Oct 2021 00:07:17 +0800
Subject: [PATCH 53/62] Update README.md

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 6caa1a85..849c5585 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,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.
 

From cb3da50e7e81238c75841aea929878a319f7cdec Mon Sep 17 00:00:00 2001
From: MrEddX <66828538+MrEddX@users.noreply.github.com>
Date: Tue, 26 Oct 2021 22:46:57 +0300
Subject: [PATCH 54/62] Update bg-BG.js

Small fixes
---
 src/languages/bg-BG.js | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/languages/bg-BG.js b/src/languages/bg-BG.js
index 0bb59077..d0681cf5 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: "Чувствителни данни, като токен кодове за известяване, се съдържат в експортирания файл. Моля, бъдете внимателни с неговото съхранение.",
@@ -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 на вътрешна стая",

From dd773aa5a20b8d8ab75c5b0c51e7e133e4b7f089 Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Tue, 26 Oct 2021 22:10:48 -0400
Subject: [PATCH 55/62] Updates based on PR comments.

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml    | 26 +++++--------------
 .github/ISSUE_TEMPLATE/bug_report.yaml      | 28 ++++++---------------
 .github/ISSUE_TEMPLATE/feature_request.yaml |  2 +-
 3 files changed, 14 insertions(+), 42 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index bde3ad8d..98b4c3b3 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -18,41 +18,27 @@ body:
       description: "Which version of Uptime-Kuma are you running?"
     validations:
       required: true
-  - type: dropdown
+  - type: input
     id: operating-system
     attributes:
       label: "💻 Operating System"
       description: "Which OS is your server/device running on?"
-      multiple: true
-      options:
-        - Linux
-        - MacOS
-        - Windows
     validations:
       required: true
-  - type: dropdown
+  - type: input
     id: browser-vendor
     attributes:
       label: "🌐 Browser"
       description: "Which browser are you running on?"
-      multiple: true
-      options:
-        - Firefox
-        - Chrome
-        - Edge
-        - Safari
-        - Other
     validations:
       required: true
-  - type: checkboxes
-    id: uses-docker
+  - type: input
+    id: docker-tag
     attributes:
       label: "🐋 Docker"
-      options:
-        - label: "Currently running in Docker?"
-          required: false
+      description: "Currently running in Docker? Specify the tag."
     validations:
-      required: true
+      required: false
   - type: input
     id: nodejs-version
     attributes:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 05591ff3..458d3b82 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -38,46 +38,32 @@ body:
       description: "Which version of Uptime-Kuma are you running?"
     validations:
       required: true
-  - type: dropdown
+  - type: input
     id: operating-system
     attributes:
       label: "💻 Operating System"
       description: "Which OS is your server/device running on?"
-      multiple: true
-      options:
-        - Linux
-        - MacOS
-        - Windows
     validations:
       required: true
-  - type: dropdown
+  - type: input
     id: browser-vendor
     attributes:
       label: "🌐 Browser"
       description: "Which browser are you running on?"
-      multiple: true
-      options:
-        - Firefox
-        - Chrome
-        - Edge
-        - Safari
-        - Other
     validations:
       required: true
-  - type: checkboxes
-    id: uses-docker
+  - type: input
+    id: docker-tag
     attributes:
       label: "🐋 Docker"
-      options:
-        - label: "Currently running in Docker?"
-          required: false
+      description: "Currently running with Docker? Which image tag are you using?"
     validations:
-      required: true
+      required: false
   - type: input
     id: nodejs-version
     attributes:
       label: "🟩 NodeJS Version"
-      description: "If running in the host, which version of NodeJS are you running?"
+      description: "Currently running with Node.js? which version of node.js are you running?"
     validations:
       required: false
   - type: textarea
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml
index ef76ff28..bca32552 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yaml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yaml
@@ -46,7 +46,7 @@ body:
     validations:
       required: false
     attributes:
-      label: "❓ Additional Context"
+      label: "📝 Additional Context"
       description: "Add any other context or screenshots about the feature request here."
       placeholder: "..."
   - type: checkboxes

From d676c782bbae2fbdd1c9e9b7ff98d2d34c09c9c5 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Wed, 27 Oct 2021 10:11:08 +0800
Subject: [PATCH 56/62] Update README.md

---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 849c5585..9177cc99 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="" />

From 698a38e773c1272a7d98b5e83968f33c2cc2a93c Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Wed, 27 Oct 2021 11:39:46 +0800
Subject: [PATCH 57/62] clear status page cache in a better place

---
 server/model/monitor.js | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/server/model/monitor.js b/server/model/monitor.js
index fb736291..126f091c 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;
             }
@@ -598,9 +602,6 @@ class Monitor extends BeanModel {
                     console.log(e);
                 }
             }
-
-            // Clear Status Page Cache
-            apicache.clear();
         }
     }
 

From 546402f3d29b6b535e446da1a1c8ea3358003d2f Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Wed, 27 Oct 2021 00:11:50 -0400
Subject: [PATCH 58/62] Added docker-image-tag field.

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml | 13 ++++++++++---
 .github/ISSUE_TEMPLATE/bug_report.yaml   | 17 ++++++++++-------
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index 98b4c3b3..c6c04490 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -33,17 +33,24 @@ body:
     validations:
       required: true
   - type: input
-    id: docker-tag
+    id: docker-version
     attributes:
       label: "🐋 Docker"
-      description: "Currently running in Docker? Specify the tag."
+      description: "If running with Docker, which version are you running?"
+    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."
     validations:
       required: false
   - type: input
     id: nodejs-version
     attributes:
       label: "🟩 NodeJS Version"
-      description: "If running in the host, which version of NodeJS are you running?"
+      description: "If running with Node.js? which version are you running?"
     validations:
       required: false
   - type: checkboxes
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 458d3b82..d4f69a25 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -3,10 +3,6 @@ description: "Submit a bug report to help us improve"
 title: "[Bug]: <title>"
 labels: [bug]
 body:
-  - type: markdown
-    attributes:
-      value: |
-        Thanks for taking the time to fill out this bug report!
   - type: textarea
     id: steps-to-reproduce
     validations:
@@ -53,17 +49,24 @@ body:
     validations:
       required: true
   - type: input
-    id: docker-tag
+    id: docker-version
     attributes:
       label: "🐋 Docker"
-      description: "Currently running with Docker? Which image tag are you using?"
+      description: "If running with Docker, which version are you running?"
+    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."
     validations:
       required: false
   - type: input
     id: nodejs-version
     attributes:
       label: "🟩 NodeJS Version"
-      description: "Currently running with Node.js? which version of node.js are you running?"
+      description: "If running with Node.js? which version are you running?"
     validations:
       required: false
   - type: textarea

From 767807dd22b618c8b4a45c7e6e1d0c862982b7c2 Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Wed, 27 Oct 2021 00:18:05 -0400
Subject: [PATCH 59/62] Added text placeholders for versions.

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml | 6 ++++++
 .github/ISSUE_TEMPLATE/bug_report.yaml   | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index c6c04490..c768ebad 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -16,6 +16,7 @@ body:
     attributes:
       label: "🐻 Uptime-Kuma version"
       description: "Which version of Uptime-Kuma are you running?"
+      placeholder: "Ex. 1.9.x"
     validations:
       required: true
   - type: input
@@ -23,6 +24,7 @@ body:
     attributes:
       label: "💻 Operating System"
       description: "Which OS is your server/device running on?"
+      placeholder: "Ex. Ubuntu 20.04"
     validations:
       required: true
   - type: input
@@ -30,6 +32,7 @@ body:
     attributes:
       label: "🌐 Browser"
       description: "Which browser are you running on?"
+      placeholder: "Ex. Firefox"
     validations:
       required: true
   - type: input
@@ -37,6 +40,7 @@ body:
     attributes:
       label: "🐋 Docker"
       description: "If running with Docker, which version are you running?"
+      placeholder: "Version can be found by running: docker version"
     validations:
       required: false
   - type: input
@@ -44,6 +48,7 @@ body:
     attributes:
       label: "🏷️ Docker Image Tag"
       description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash."
+      placeholder: "1, latest, debian, alpine. Image hash can be obtained with: docker images --digests"
     validations:
       required: false
   - type: input
@@ -51,6 +56,7 @@ body:
     attributes:
       label: "🟩 NodeJS Version"
       description: "If running with Node.js? which version are you running?"
+      placeholder: "14.x"
     validations:
       required: false
   - type: checkboxes
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index d4f69a25..9fcab1f2 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -32,6 +32,7 @@ body:
     attributes:
       label: "🐻 Uptime-Kuma version"
       description: "Which version of Uptime-Kuma are you running?"
+      placeholder: "Ex. 1.9.x"
     validations:
       required: true
   - type: input
@@ -39,6 +40,7 @@ body:
     attributes:
       label: "💻 Operating System"
       description: "Which OS is your server/device running on?"
+      placeholder: "Ex. Ubuntu 20.04"
     validations:
       required: true
   - type: input
@@ -46,6 +48,7 @@ body:
     attributes:
       label: "🌐 Browser"
       description: "Which browser are you running on?"
+      placeholder: "Ex. Firefox"
     validations:
       required: true
   - type: input
@@ -53,6 +56,7 @@ body:
     attributes:
       label: "🐋 Docker"
       description: "If running with Docker, which version are you running?"
+      placeholder: "Version can be found by running: docker version"
     validations:
       required: false
   - type: input
@@ -60,6 +64,7 @@ body:
     attributes:
       label: "🏷️ Docker Image Tag"
       description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash."
+      placeholder: "1, latest, debian, alpine. Image hash can be obtained with: docker images --digests"
     validations:
       required: false
   - type: input
@@ -67,6 +72,7 @@ body:
     attributes:
       label: "🟩 NodeJS Version"
       description: "If running with Node.js? which version are you running?"
+      placeholder: "14.x"
     validations:
       required: false
   - type: textarea

From 6c542edfc95cfed5414248c4421b802e0b7aa83a Mon Sep 17 00:00:00 2001
From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com>
Date: Wed, 27 Oct 2021 00:23:13 -0400
Subject: [PATCH 60/62] Add examples for version and image tag.

---
 .github/ISSUE_TEMPLATE/ask-for-help.yaml | 4 ++--
 .github/ISSUE_TEMPLATE/bug_report.yaml   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/ISSUE_TEMPLATE/ask-for-help.yaml b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
index c768ebad..dd1bcaf7 100644
--- a/.github/ISSUE_TEMPLATE/ask-for-help.yaml
+++ b/.github/ISSUE_TEMPLATE/ask-for-help.yaml
@@ -40,7 +40,7 @@ body:
     attributes:
       label: "🐋 Docker"
       description: "If running with Docker, which version are you running?"
-      placeholder: "Version can be found by running: docker version"
+      placeholder: "Ex. 20.10.9"
     validations:
       required: false
   - type: input
@@ -48,7 +48,7 @@ body:
     attributes:
       label: "🏷️ Docker Image Tag"
       description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash."
-      placeholder: "1, latest, debian, alpine. Image hash can be obtained with: docker images --digests"
+      placeholder: "Ex. 1.9.1"
     validations:
       required: false
   - type: input
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 9fcab1f2..5e3b5bf8 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -56,7 +56,7 @@ body:
     attributes:
       label: "🐋 Docker"
       description: "If running with Docker, which version are you running?"
-      placeholder: "Version can be found by running: docker version"
+      placeholder: "Ex. 20.10.9"
     validations:
       required: false
   - type: input
@@ -64,7 +64,7 @@ body:
     attributes:
       label: "🏷️ Docker Image Tag"
       description: "Which Docker image tag are you using? If running '1' or 'latest', please specify image hash."
-      placeholder: "1, latest, debian, alpine. Image hash can be obtained with: docker images --digests"
+      placeholder: "Ex. 1.9.1"
     validations:
       required: false
   - type: input

From 234fba397826f0237dca21bb12d0fec86db169db Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Wed, 27 Oct 2021 12:31:18 +0800
Subject: [PATCH 61/62] Update SECURITY.md

---
 SECURITY.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/SECURITY.md b/SECURITY.md
index a0b2562f..7b9bfca4 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
 

From 640b6e5b1c587b14d1146a392d953e551b5b34f9 Mon Sep 17 00:00:00 2001
From: Louis Lam <louislam@users.noreply.github.com>
Date: Wed, 27 Oct 2021 14:08:44 +0800
Subject: [PATCH 62/62] prevent monitor dead for unexpected error

---
 server/model/monitor.js | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/server/model/monitor.js b/server/model/monitor.js
index 126f091c..2f28e5b9 100644
--- a/server/model/monitor.js
+++ b/server/model/monitor.js
@@ -387,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();
         }
     }