From 7fee4a7ea73aeb0930078acd5790efbb60ebd163 Mon Sep 17 00:00:00 2001
From: Ponkhy <github@myon.lu>
Date: Sat, 11 Sep 2021 21:53:17 +0200
Subject: [PATCH 1/5] Added import options

---
 server/server.js       | 104 +++++++++++++++++++++++++----------------
 src/languages/de-DE.js |   8 +++-
 src/languages/en.js    |   8 +++-
 src/mixins/socket.js   |   4 +-
 src/pages/Settings.vue |  33 +++++++++++--
 5 files changed, 111 insertions(+), 46 deletions(-)

diff --git a/server/server.js b/server/server.js
index 2949c4be7..e4ad586aa 100644
--- a/server/server.js
+++ b/server/server.js
@@ -594,7 +594,7 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString();
             }
         });
 
-        socket.on("uploadBackup", async (uploadedJSON, callback) => {
+        socket.on("uploadBackup", async (uploadedJSON, importHandle, callback) => {
             try {
                 checkLogin(socket)
 
@@ -602,54 +602,80 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString();
 
                 console.log(`Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`)
 
-                let notificationList = backupData.notificationList;
-                let monitorList = backupData.monitorList;
+                let notificationListData = backupData.notificationList;
+                let monitorListData = backupData.monitorList;
 
-                if (notificationList.length >= 1) {
-                    for (let i = 0; i < notificationList.length; i++) {
-                        let notification = JSON.parse(notificationList[i].config);
-                        await Notification.save(notification, null, socket.userID)
+                if (importHandle == "overwrite") {
+                    for (let id in monitorList) {
+                        let monitor = monitorList[id]
+                        await monitor.stop()
+                    }
+                    await R.exec("DELETE FROM heartbeat");
+                    await R.exec("DELETE FROM monitor_notification");
+                    await R.exec("DELETE FROM monitor_tls_info");
+                    await R.exec("DELETE FROM notification");
+                    await R.exec("DELETE FROM monitor");
+                }
+
+                if (notificationListData.length >= 1) {
+                    let notificationNameList = await R.getAll("SELECT name FROM notification");
+                    let notificationNameListString = JSON.stringify(notificationNameList);
+
+                    for (let i = 0; i < notificationListData.length; i++) {
+                        if ((importHandle == "skip" && notificationNameListString.includes(notificationListData[i].name) == false) || importHandle == "keep" || importHandle == "overwrite") {
+
+                            let notification = JSON.parse(notificationListData[i].config);
+                            await Notification.save(notification, null, socket.userID)
+
+                        }
                     }
                 }
 
-                if (monitorList.length >= 1) {
-                    for (let i = 0; i < monitorList.length; i++) {
-                        let monitor = {
-                            name: monitorList[i].name,
-                            type: monitorList[i].type,
-                            url: monitorList[i].url,
-                            interval: monitorList[i].interval,
-                            hostname: monitorList[i].hostname,
-                            maxretries: monitorList[i].maxretries,
-                            port: monitorList[i].port,
-                            keyword: monitorList[i].keyword,
-                            ignoreTls: monitorList[i].ignoreTls,
-                            upsideDown: monitorList[i].upsideDown,
-                            maxredirects: monitorList[i].maxredirects,
-                            accepted_statuscodes: monitorList[i].accepted_statuscodes,
-                            dns_resolve_type: monitorList[i].dns_resolve_type,
-                            dns_resolve_server: monitorList[i].dns_resolve_server,
-                            notificationIDList: {},
-                        }
+                if (monitorListData.length >= 1) {
+                    let monitorNameList = await R.getAll("SELECT name FROM monitor");
+                    let monitorNameListString = JSON.stringify(monitorNameList);
 
-                        let bean = R.dispense("monitor")
+                    for (let i = 0; i < monitorListData.length; i++) {
+                        if ((importHandle == "skip" && monitorNameListString.includes(monitorListData[i].name) == false) || importHandle == "keep" || importHandle == "overwrite") {
 
-                        let notificationIDList = monitor.notificationIDList;
-                        delete monitor.notificationIDList;
+                            let monitor = {
+                                name: monitorListData[i].name,
+                                type: monitorListData[i].type,
+                                url: monitorListData[i].url,
+                                interval: monitorListData[i].interval,
+                                hostname: monitorListData[i].hostname,
+                                maxretries: monitorListData[i].maxretries,
+                                port: monitorListData[i].port,
+                                keyword: monitorListData[i].keyword,
+                                ignoreTls: monitorListData[i].ignoreTls,
+                                upsideDown: monitorListData[i].upsideDown,
+                                maxredirects: monitorListData[i].maxredirects,
+                                accepted_statuscodes: monitorListData[i].accepted_statuscodes,
+                                dns_resolve_type: monitorListData[i].dns_resolve_type,
+                                dns_resolve_server: monitorListData[i].dns_resolve_server,
+                                notificationIDList: {},
+                            }
 
-                        monitor.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes);
-                        delete monitor.accepted_statuscodes;
+                            let bean = R.dispense("monitor")
 
-                        bean.import(monitor)
-                        bean.user_id = socket.userID
-                        await R.store(bean)
+                            let notificationIDList = monitor.notificationIDList;
+                            delete monitor.notificationIDList;
 
-                        await updateMonitorNotification(bean.id, notificationIDList)
+                            monitor.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes);
+                            delete monitor.accepted_statuscodes;
+
+                            bean.import(monitor)
+                            bean.user_id = socket.userID
+                            await R.store(bean)
+
+                            await updateMonitorNotification(bean.id, notificationIDList)
+
+                            if (monitorListData[i].active == 1) {
+                                await startMonitor(socket.userID, bean.id);
+                            } else {
+                                await pauseMonitor(socket.userID, bean.id);
+                            }
 
-                        if (monitorList[i].active == 1) {
-                            await startMonitor(socket.userID, bean.id);
-                        } else {
-                            await pauseMonitor(socket.userID, bean.id);
                         }
                     }
 
diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js
index a8cf5a7c0..083d939a4 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -128,5 +128,11 @@ export default {
     backupDescription3: "Sensible Daten wie Benachrichtigungstoken sind in der Exportdatei enthalten, bitte bewahre sie sorgfältig auf.",
     alertNoFile: "Bitte wähle eine Datei zum importieren aus.",
     alertWrongFileType: "Bitte wähle eine JSON Datei aus.",
-    "Clear all statistics": "Lösche alle Statistiken"
+    "Clear all statistics": "Lösche alle Statistiken",
+    importHandleDescription: "Wähle 'Vorhandene überspringen' aus, wenn jeder Monitor oder Benachrichtigung mit demselben Namen übersprungen werden soll. 'Überschreiben' löscht jeden vorhandenen Monitor sowie Benachrichtigungen.",
+    "Skip existing": "Vorhandene überspringen",
+    "Overwrite": "Überschreiben",
+    "Import Options": "Import Optionen",
+    confirmImportMsg: "Möchtest du das Backup wirklich importieren? Bitte stelle sicher, dass die richtige Import Option ausgewählt ist.",
+    "Keep both": "Beide behalten",
 }
diff --git a/src/languages/en.js b/src/languages/en.js
index 585736857..14bf20b2d 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -20,6 +20,8 @@ export default {
     clearEventsMsg: "Are you sure want to delete all events for this monitor?",
     clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
+    importHandleDescription: "Choose 'Skip Existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
+    confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
     Settings: "Settings",
     Dashboard: "Dashboard",
     "New Update": "New Update",
@@ -128,5 +130,9 @@ export default {
     backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.",
     alertNoFile: "Please select a file to import.",
     alertWrongFileType: "Please select a JSON file.",
-    "Clear all statistics": "Clear all Statistics"
+    "Clear all statistics": "Clear all Statistics",
+    "Skip existing": "Skip existing",
+    "Overwrite": "Overwrite",
+    "Import Options": "Import Options",
+    "Keep both": "Keep both",
 }
diff --git a/src/mixins/socket.js b/src/mixins/socket.js
index 9771db0d2..e0088a59f 100644
--- a/src/mixins/socket.js
+++ b/src/mixins/socket.js
@@ -256,8 +256,8 @@ export default {
             this.importantHeartbeatList = {}
         },
 
-        uploadBackup(uploadedJSON, callback) {
-            socket.emit("uploadBackup", uploadedJSON, callback)
+        uploadBackup(uploadedJSON, importHandle, callback) {
+            socket.emit("uploadBackup", uploadedJSON, importHandle, callback)
         },
 
         clearEvents(monitorID, callback) {
diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue
index cd1a95bc2..9502f11ce 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -127,14 +127,33 @@
                                 ({{ $t("backupDescription2") }}) <br />
                             </p>
 
-                            <div class="input-group mb-3">
+                            <div class="input-group mb-2">
                                 <button class="btn btn-outline-primary" @click="downloadBackup">{{ $t("Export") }}</button>
-                                <button type="button" class="btn btn-outline-primary" :disabled="processing" @click="importBackup">
+                                <button type="button" class="btn btn-outline-primary" :disabled="processing" @click="confirmImport">
                                     <div v-if="processing" class="spinner-border spinner-border-sm me-1"></div>
                                     {{ $t("Import") }}
                                 </button>
                                 <input id="importBackup" type="file" class="form-control" accept="application/json">
                             </div>
+
+                            <label class="form-label">{{ $t("Import Options") }}:</label>
+                            <br>
+                            <div class="form-check form-check-inline">
+                                <input v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" id="radioKeep" value="keep">
+                                <label class="form-check-label" for="radioKeep">{{ $t("Keep both") }}</label>
+                            </div>
+                            <div class="form-check form-check-inline">
+                                <input v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" id="radioSkip" value="skip">
+                                <label class="form-check-label" for="radioSkip">{{ $t("Skip existing") }}</label>
+                            </div>
+                            <div class="form-check form-check-inline">
+                                <input v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" id="radioOverwrite" value="overwrite">
+                                <label class="form-check-label" for="radioOverwrite">{{ $t("Overwrite") }}</label>
+                            </div>
+                            <div class="form-text mb-2">
+                                {{ $t("importHandleDescription") }}
+                            </div>
+
                             <div v-if="importAlert" class="alert alert-danger mt-3" style="padding: 6px 16px;">
                                 {{ importAlert }}
                             </div>
@@ -259,6 +278,9 @@
             <Confirm ref="confirmClearStatistics" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="clearStatistics">
                 {{ $t("confirmClearStatisticsMsg") }}
             </Confirm>
+            <Confirm ref="confirmImport" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="importBackup">
+                {{ $t("confirmImportMsg") }}
+            </Confirm>
         </div>
     </transition>
 </template>
@@ -297,6 +319,7 @@ export default {
             },
             loaded: false,
             importAlert: null,
+            importHandle: "skip",
             processing: false,
         }
     },
@@ -363,6 +386,10 @@ export default {
             this.$refs.confirmClearStatistics.show();
         },
 
+        confirmImport() {
+            this.$refs.confirmImport.show();
+        },
+
         disableAuth() {
             this.settings.disableAuth = true;
             this.saveSettings();
@@ -408,7 +435,7 @@ export default {
             fileReader.readAsText(uploadItem.item(0));
 
             fileReader.onload = item => {
-                this.$root.uploadBackup(item.target.result, (res) => {
+                this.$root.uploadBackup(item.target.result, this.importHandle, (res) => {
                     this.processing = false;
 
                     if (res.ok) {

From 862672731f9c1034f8e4d53d4a05802262baf356 Mon Sep 17 00:00:00 2001
From: Ponkhy <github@myon.lu>
Date: Sat, 11 Sep 2021 22:06:26 +0200
Subject: [PATCH 2/5] Minor typo fix

---
 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 14bf20b2d..0644610de 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -20,7 +20,7 @@ export default {
     clearEventsMsg: "Are you sure want to delete all events for this monitor?",
     clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
     confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
-    importHandleDescription: "Choose 'Skip Existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
+    importHandleDescription: "Choose 'Skip existing' if you want to skip every monitor or notification with the same name. 'Overwrite' will delete every existing monitor and notification.",
     confirmImportMsg: "Are you sure to import the backup? Please make sure you've selected the right import option.",
     Settings: "Settings",
     Dashboard: "Dashboard",

From ea723c7595c56c621f33a6b9c2988c178809efed Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <adam.stachowicz@fingo.info>
Date: Sun, 12 Sep 2021 21:35:37 +0200
Subject: [PATCH 3/5] Separate import and export. Fix ESLint

---
 src/pages/Settings.vue | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue
index 84c3f8b75..8b013c5f9 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -128,46 +128,54 @@
                                 <button class="btn btn-primary me-2" type="button" @click="$refs.TwoFADialog.show()">{{ $t("2FA Settings") }}</button>
                             </div>
 
-                            <h2 class="mt-5 mb-2">{{ $t("Import/Export Backup") }}</h2>
+                            <h2 class="mt-5 mb-2">{{ $t("Export Backup") }}</h2>
 
                             <p>
                                 {{ $t("backupDescription") }} <br />
                                 ({{ $t("backupDescription2") }}) <br />
                             </p>
 
-                            <div class="input-group mb-2">
-                                <button class="btn btn-outline-primary" @click="downloadBackup">{{ $t("Export") }}</button>
-                                <button type="button" class="btn btn-outline-primary" :disabled="processing" @click="confirmImport">
-                                    <div v-if="processing" class="spinner-border spinner-border-sm me-1"></div>
-                                    {{ $t("Import") }}
-                                </button>
-                                <input id="importBackup" type="file" class="form-control" accept="application/json">
+                            <div class="d-flex mb-2 justify-content-center">
+                                <button class="btn btn-primary" @click="downloadBackup">{{ $t("Export") }}</button>
                             </div>
 
+                            <p><strong>{{ $t("backupDescription3") }}</strong></p>
+
+                            <h2 class="mt-5 mb-2">{{ $t("Import Backup") }}</h2>
+
                             <label class="form-label">{{ $t("Import Options") }}:</label>
                             <br>
                             <div class="form-check form-check-inline">
-                                <input v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" id="radioKeep" value="keep">
+                                <input id="radioKeep" v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" value="keep">
                                 <label class="form-check-label" for="radioKeep">{{ $t("Keep both") }}</label>
                             </div>
                             <div class="form-check form-check-inline">
-                                <input v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" id="radioSkip" value="skip">
+                                <input id="radioSkip" v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" value="skip">
                                 <label class="form-check-label" for="radioSkip">{{ $t("Skip existing") }}</label>
                             </div>
                             <div class="form-check form-check-inline">
-                                <input v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" id="radioOverwrite" value="overwrite">
+                                <input id="radioOverwrite" v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" value="overwrite">
                                 <label class="form-check-label" for="radioOverwrite">{{ $t("Overwrite") }}</label>
                             </div>
                             <div class="form-text mb-2">
                                 {{ $t("importHandleDescription") }}
                             </div>
 
+                            <div class="mb-2">
+                                <input id="importBackup" type="file" class="form-control" accept="application/json">
+                            </div>
+
+                            <div class="input-group mb-2 justify-content-end">
+                                <button type="button" class="btn btn-outline-primary" :disabled="processing" @click="confirmImport">
+                                    <div v-if="processing" class="spinner-border spinner-border-sm me-1"></div>
+                                    {{ $t("Import") }}
+                                </button>
+                            </div>
+
                             <div v-if="importAlert" class="alert alert-danger mt-3" style="padding: 6px 16px;">
                                 {{ importAlert }}
                             </div>
 
-                            <p><strong>{{ $t("backupDescription3") }}</strong></p>
-
                             <h2 class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
 
                             <div class="mb-3">

From 7199bb5ead275307f3443980472df069ed6a1e40 Mon Sep 17 00:00:00 2001
From: Adam Stachowicz <adam.stachowicz@fingo.info>
Date: Sun, 12 Sep 2021 23:11:07 +0200
Subject: [PATCH 4/5] Remove unused i18n key

---
 src/languages/da-DK.js   | 1 -
 src/languages/de-DE.js   | 3 +--
 src/languages/en.js      | 6 +++---
 src/languages/es-ES.js   | 1 -
 src/languages/et-EE.js   | 1 -
 src/languages/fr-FR.js   | 1 -
 src/languages/it-IT.js   | 1 -
 src/languages/ja.js      | 1 -
 src/languages/ko-KR.js   | 1 -
 src/languages/nl-NL.js   | 1 -
 src/languages/pl.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/zh-CN.js   | 1 -
 src/languages/zh-HK.js   | 1 -
 src/pages/Settings.vue   | 2 +-
 18 files changed, 5 insertions(+), 21 deletions(-)

diff --git a/src/languages/da-DK.js b/src/languages/da-DK.js
index 6e8069aa1..eefe7467b 100644
--- a/src/languages/da-DK.js
+++ b/src/languages/da-DK.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For hver ny overvåger aktiveres denne underretning som standard. Du kan stadig deaktivere underretningen separat for hver skærm.",
     "Default enabled": "Standard aktiveret",
     "Also apply to existing monitors": "Anvend også på eksisterende overvågere",
-    "Import/Export Backup": " Importér/Eksportér sikkerhedskopi",
     Export: "Eksport",
     Import: "Import",
     backupDescription: "Du kan sikkerhedskopiere alle Overvågere og alle underretninger til en JSON-fil.",
diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js
index e401f2bf8..95cc3d69a 100644
--- a/src/languages/de-DE.js
+++ b/src/languages/de-DE.js
@@ -113,7 +113,6 @@ export default {
     "Create your admin account": "Erstelle dein Admin Konto",
     "Repeat Password": "Wiederhole das Passwort",
     "Resource Record Type": "Resource Record Type",
-    "Import/Export Backup": "Import/Export Backup",
     "Export": "Export",
     "Import": "Import",
     respTime: "Antw. Zeit (ms)",
@@ -132,7 +131,7 @@ export default {
     importHandleDescription: "Wähle 'Vorhandene überspringen' aus, wenn jeder Monitor oder Benachrichtigung mit demselben Namen übersprungen werden soll. 'Überschreiben' löscht jeden vorhandenen Monitor sowie Benachrichtigungen.",
     "Skip existing": "Vorhandene überspringen",
     "Overwrite": "Überschreiben",
-    "Import Options": "Import Optionen",
+    "Options": "Optionen",
     confirmImportMsg: "Möchtest du das Backup wirklich importieren? Bitte stelle sicher, dass die richtige Import Option ausgewählt ist.",
     "Keep both": "Beide behalten",
     twoFAVerifyLabel: "Bitte trage deinen Token ein um zu verifizieren das 2FA funktioniert",
diff --git a/src/languages/en.js b/src/languages/en.js
index c81db3105..fc9b60011 100644
--- a/src/languages/en.js
+++ b/src/languages/en.js
@@ -117,7 +117,8 @@ export default {
     "Last Result": "Last Result",
     "Create your admin account": "Create your admin account",
     "Repeat Password": "Repeat Password",
-    "Import/Export Backup": "Import/Export Backup",
+    "Import Backup": "Import Backup",
+    "Export Backup": "Export Backup",
     Export: "Export",
     Import: "Import",
     respTime: "Resp. Time (ms)",
@@ -137,7 +138,7 @@ export default {
     "Clear all statistics": "Clear all Statistics",
     "Skip existing": "Skip existing",
     "Overwrite": "Overwrite",
-    "Import Options": "Import Options",
+    "Options": "Options",
     "Keep both": "Keep both",
     "Verify Token": "Verify Token",
     "Setup 2FA": "Setup 2FA",
@@ -149,5 +150,4 @@ export default {
     Inactive: "Inactive",
     Token: "Token",
     "Show URI": "Show URI",
-    "Clear all statistics": "Clear all Statistics"
 }
diff --git a/src/languages/es-ES.js b/src/languages/es-ES.js
index b52c1654f..cef00568f 100644
--- a/src/languages/es-ES.js
+++ b/src/languages/es-ES.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/et-EE.js b/src/languages/et-EE.js
index fca24a33d..9c28730df 100644
--- a/src/languages/et-EE.js
+++ b/src/languages/et-EE.js
@@ -113,7 +113,6 @@ export default {
     clearEventsMsg: "Kas soovid seire kõik sündmused kustutada?",
     clearHeartbeatsMsg: "Kas soovid seire kõik tuksed kustutada?",
     confirmClearStatisticsMsg: "Kas soovid KÕIK statistika kustutada?",
-    "Import/Export Backup": "Impordi/Ekspordi varukoopia",
     Export: "Eksport",
     Import: "Import",
     "Default enabled": "Kasuta vaikimisi",
diff --git a/src/languages/fr-FR.js b/src/languages/fr-FR.js
index 4821b818c..44f20e9ce 100644
--- a/src/languages/fr-FR.js
+++ b/src/languages/fr-FR.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/it-IT.js b/src/languages/it-IT.js
index 1d337810c..5cad910d9 100644
--- a/src/languages/it-IT.js
+++ b/src/languages/it-IT.js
@@ -118,7 +118,6 @@ export default {
     Heartbeats: "Controlli",
     "Auto Get": "Auto Get",
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     "Default enabled": "Default enabled",
diff --git a/src/languages/ja.js b/src/languages/ja.js
index 6d0693d5a..11f4ab2d5 100644
--- a/src/languages/ja.js
+++ b/src/languages/ja.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/ko-KR.js b/src/languages/ko-KR.js
index 68479ade1..2bf6cd5d3 100644
--- a/src/languages/ko-KR.js
+++ b/src/languages/ko-KR.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/nl-NL.js b/src/languages/nl-NL.js
index 48e3b3a29..624a4ec68 100644
--- a/src/languages/nl-NL.js
+++ b/src/languages/nl-NL.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/pl.js b/src/languages/pl.js
index 3029b3497..dbaed36ab 100644
--- a/src/languages/pl.js
+++ b/src/languages/pl.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/ru-RU.js b/src/languages/ru-RU.js
index 7f5eae760..5b81f6fcd 100644
--- a/src/languages/ru-RU.js
+++ b/src/languages/ru-RU.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/sr-latn.js b/src/languages/sr-latn.js
index 3dd73d2cc..b8e19e3e6 100644
--- a/src/languages/sr-latn.js
+++ b/src/languages/sr-latn.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/sr.js b/src/languages/sr.js
index 6931d272e..b00de38aa 100644
--- a/src/languages/sr.js
+++ b/src/languages/sr.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/sv-SE.js b/src/languages/sv-SE.js
index f8749e289..f735dbbfe 100644
--- a/src/languages/sv-SE.js
+++ b/src/languages/sv-SE.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "For every new monitor this notification will be enabled by default. You can still disable the notification separately for each monitor.",
     "Default enabled": "Default enabled",
     "Also apply to existing monitors": "Also apply to existing monitors",
-    "Import/Export Backup": "Import/Export Backup",
     Export: "Export",
     Import: "Import",
     backupDescription: "You can backup all monitors and all notifications into a JSON file.",
diff --git a/src/languages/zh-CN.js b/src/languages/zh-CN.js
index 1d15c3d95..085b64e31 100644
--- a/src/languages/zh-CN.js
+++ b/src/languages/zh-CN.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "新的监控项将默认启用,你也可以在每个监控项中分别设置",
     "Default enabled": "默认开启",
     "Also apply to existing monitors": "应用到所有监控项",
-    "Import/Export Backup": "导入/导出备份",
     Export: "导出",
     Import: "导入",
     backupDescription: "你可以将所有的监控项和消息通知备份到一个 JSON 文件中",
diff --git a/src/languages/zh-HK.js b/src/languages/zh-HK.js
index 314b6e696..0a108be04 100644
--- a/src/languages/zh-HK.js
+++ b/src/languages/zh-HK.js
@@ -120,7 +120,6 @@ export default {
     enableDefaultNotificationDescription: "新增監測器時這個通知會預設啟用,當然每個監測器亦可分別控制開關。",
     "Default enabled": "預設通知",
     "Also apply to existing monitors": "同時取用至目前所有監測器",
-    "Import/Export Backup": "匯入/匯出 備份",
     Export: "匯出",
     Import: "匯入",
     backupDescription: "您可以備份所有監測器及所有通知。",
diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue
index 8b013c5f9..aefdd4468 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -143,7 +143,7 @@
 
                             <h2 class="mt-5 mb-2">{{ $t("Import Backup") }}</h2>
 
-                            <label class="form-label">{{ $t("Import Options") }}:</label>
+                            <label class="form-label">{{ $t("Options") }}:</label>
                             <br>
                             <div class="form-check form-check-inline">
                                 <input id="radioKeep" v-model="importHandle" class="form-check-input" type="radio" name="radioImportHandle" value="keep">

From f679c1cbafcb24e3852c6fcedc1ae74bbc5ef152 Mon Sep 17 00:00:00 2001
From: Ponkhy <github@myon.lu>
Date: Wed, 15 Sep 2021 12:01:30 +0200
Subject: [PATCH 5/5] Export button align left

---
 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 aefdd4468..79cb0cc15 100644
--- a/src/pages/Settings.vue
+++ b/src/pages/Settings.vue
@@ -135,7 +135,7 @@
                                 ({{ $t("backupDescription2") }}) <br />
                             </p>
 
-                            <div class="d-flex mb-2 justify-content-center">
+                            <div class="mb-2">
                                 <button class="btn btn-primary" @click="downloadBackup">{{ $t("Export") }}</button>
                             </div>