From 205e16a96d3b21b8783ee6aa544c417dd12ee69c Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Fri, 20 Jun 2025 02:54:09 +0530 Subject: [PATCH 01/32] Resolved Filter in FE --- .../Pages/Incidents/Components/IncidentTable/index.jsx | 10 ++++++---- .../Pages/Incidents/Components/OptionsHeader/index.jsx | 7 +++++++ client/src/locales/en.json | 3 ++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx index 3b2e07238..b3e2d2f30 100644 --- a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx +++ b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx @@ -32,15 +32,17 @@ const IncidentTable = ({ const selectedMonitorDetails = monitors?.[selectedMonitor]; const selectedMonitorType = selectedMonitorDetails?.type; + const status = filter === "resolved" ? true : false; + const [checksMonitor, checksCountMonitor, isLoadingMonitor, networkErrorMonitor] = useFetchChecksByMonitor({ monitorId: selectedMonitor === "0" ? undefined : selectedMonitor, type: selectedMonitorType, - status: false, + status: status, sortOrder: "desc", limit: null, dateRange, - filter: filter, + filter: filter === "resolved" ? "resolve" : filter, page: page, rowsPerPage: rowsPerPage, enabled: selectedMonitor !== "0", @@ -48,11 +50,11 @@ const IncidentTable = ({ const [checksTeam, checksCountTeam, isLoadingTeam, networkErrorTeam] = useFetchChecksTeam({ - status: false, + status: status, sortOrder: "desc", limit: null, dateRange, - filter: filter, + filter: filter === "resolved" ? "resolve" : filter, page: page, rowsPerPage: rowsPerPage, enabled: selectedMonitor === "0", diff --git a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx index 20140e8c4..08a9bcf1c 100644 --- a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx +++ b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx @@ -87,6 +87,13 @@ const OptionsHeader = ({ > {t("incidentsOptionsHeaderFilterCannotResolve")} + diff --git a/client/src/locales/en.json b/client/src/locales/en.json index ff878c3da..ec943dd65 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -187,6 +187,7 @@ "incidentsOptionsHeaderFilterAll": "All", "incidentsOptionsHeaderFilterDown": "Down", "incidentsOptionsHeaderFilterCannotResolve": "Cannot resolve", + "incidentsOptionsHeaderFilterResolved": "Resolved", "incidentsOptionsHeaderShow": "Show:", "incidentsOptionsHeaderLastHour": "Last hour", "incidentsOptionsHeaderLastDay": "Last day", @@ -746,4 +747,4 @@ "settingsEmailPool": "Pool - Enable connection pooling", "sendTestNotifications": "Send test notifications", "selectAll": "Select all" -} \ No newline at end of file +} From e8908351a27c0b0292df44aa96e8ebc185b40a39 Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Fri, 20 Jun 2025 15:39:13 +0530 Subject: [PATCH 02/32] Route for Updating a single Incident Status --- .../Components/IncidentTable/index.jsx | 4 +-- client/src/Utils/NetworkService.js | 18 +++++++++++ server/controllers/checkController.js | 27 ++++++++++++++++- server/db/mongo/modules/checkModule.js | 30 +++++++++++++++++-- server/routes/checkRoute.js | 2 ++ server/validation/joi.js | 5 ++++ 6 files changed, 81 insertions(+), 5 deletions(-) diff --git a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx index b3e2d2f30..b4bfbe9dc 100644 --- a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx +++ b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx @@ -42,7 +42,7 @@ const IncidentTable = ({ sortOrder: "desc", limit: null, dateRange, - filter: filter === "resolved" ? "resolve" : filter, + filter: filter === "resolved" ? "all" : filter, page: page, rowsPerPage: rowsPerPage, enabled: selectedMonitor !== "0", @@ -54,7 +54,7 @@ const IncidentTable = ({ sortOrder: "desc", limit: null, dateRange, - filter: filter === "resolved" ? "resolve" : filter, + filter: filter === "resolved" ? "all" : filter, page: page, rowsPerPage: rowsPerPage, enabled: selectedMonitor === "0", diff --git a/client/src/Utils/NetworkService.js b/client/src/Utils/NetworkService.js index eee795268..8625b69e3 100644 --- a/client/src/Utils/NetworkService.js +++ b/client/src/Utils/NetworkService.js @@ -598,6 +598,24 @@ class NetworkService { return this.axiosInstance.get(`/checks/team?${params.toString()}`); }; + /** + * ************************************ + * Update the status of a check + * ************************************ + * + * @async + * @param {Object} config - The configuration object. + * @param {string} config.checkId - The ID of the check to update. + * @param {boolean} config.status - The status to update the check to. + * @returns {Promise} The response from the axios PUT request. + * + */ + async updateCheckStatus(config) { + return this.axiosInstance.put(`/checks/${config.checkId}`, { + status: config.status, + }); + } + /** * ************************************ * Get all checks for a given user diff --git a/server/controllers/checkController.js b/server/controllers/checkController.js index 387839beb..0dece0a6d 100755 --- a/server/controllers/checkController.js +++ b/server/controllers/checkController.js @@ -8,6 +8,7 @@ import { deleteChecksParamValidation, deleteChecksByTeamIdParamValidation, updateChecksTTLBodyValidation, + updateCheckStatusBodyValidation, } from "../validation/joi.js"; import jwt from "jsonwebtoken"; import { getTokenFromHeaders } from "../utils/utils.js"; @@ -85,7 +86,7 @@ class CheckController { return; } try { - let { sortOrder, dateRange, filter, page, rowsPerPage } = req.query; + let { sortOrder, dateRange, filter, page, rowsPerPage, status } = req.query; const { teamId } = req.user; const checkData = await this.db.getChecksByTeam({ @@ -95,6 +96,7 @@ class CheckController { page, rowsPerPage, teamId, + status, }); return res.success({ msg: this.stringService.checkGet, @@ -105,6 +107,29 @@ class CheckController { } }; + updateCheckStatus = async (req, res, next) => { + try { + await updateCheckStatusBodyValidation.validateAsync(req.body); + } catch (error) { + next(handleValidationError(error, SERVICE_NAME)); + return; + } + + try { + const { checkId } = req.params; + const { status } = req.body; + + const updatedCheck = await this.db.updateCheckStatus(checkId, status); + + return res.success({ + msg: this.stringService.checkUpdateStatus, + data: updatedCheck, + }); + } catch (error) { + next(handleError(error, SERVICE_NAME, "updateCheckStatus")); + } + }; + deleteChecks = async (req, res, next) => { try { await deleteChecksParamValidation.validateAsync(req.params); diff --git a/server/db/mongo/modules/checkModule.js b/server/db/mongo/modules/checkModule.js index f409fd3d2..97f088953 100755 --- a/server/db/mongo/modules/checkModule.js +++ b/server/db/mongo/modules/checkModule.js @@ -68,7 +68,7 @@ const getChecksByMonitor = async ({ status, }) => { try { - status = typeof status !== "undefined" ? false : undefined; + status = status === "true" ? true : status === "false" ? false : undefined; page = parseInt(page); rowsPerPage = parseInt(rowsPerPage); // Match @@ -156,13 +156,15 @@ const getChecksByTeam = async ({ page, rowsPerPage, teamId, + status, }) => { try { + status = status === "true" ? true : false; page = parseInt(page); rowsPerPage = parseInt(rowsPerPage); const matchStage = { teamId: ObjectId.createFromHexString(teamId), - status: false, + status: status, ...(dateRangeLookup[dateRange] && { createdAt: { $gte: dateRangeLookup[dateRange], @@ -236,6 +238,29 @@ const getChecksByTeam = async ({ } }; +/** + * Update the status of a check + * @async + * @param {string} checkId + * @param {boolean} status + * @returns {Promise} + * @throws {Error} + */ +const updateCheckStatus = async (checkId, status) => { + try { + const updatedCheck = await Check.findOneAndUpdate( + { _id: checkId }, + { status }, + { new: true } + ); + return updatedCheck; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "updateCheckStatus"; + throw error; + } +}; + /** * Delete all checks for a monitor * @async @@ -317,6 +342,7 @@ export { createChecks, getChecksByMonitor, getChecksByTeam, + updateCheckStatus, deleteChecks, deleteChecksByTeamId, updateChecksTTL, diff --git a/server/routes/checkRoute.js b/server/routes/checkRoute.js index aedca991a..d2b0590a0 100755 --- a/server/routes/checkRoute.js +++ b/server/routes/checkRoute.js @@ -20,6 +20,8 @@ class CheckRoutes { this.router.get("/:monitorId", this.checkController.getChecksByMonitor); + this.router.put("/:checkId", this.checkController.updateCheckStatus); + this.router.post( "/:monitorId", verifyOwnership(Monitor, "monitorId"), diff --git a/server/validation/joi.js b/server/validation/joi.js index e684cefa2..3c893260d 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -289,6 +289,10 @@ const createCheckBodyValidation = joi.object({ message: joi.string().required(), }); +const updateCheckStatusBodyValidation = joi.object({ + status: joi.boolean(), +}); + const getChecksParamValidation = joi.object({ monitorId: joi.string().required(), }); @@ -662,6 +666,7 @@ export { getChecksQueryValidation, getTeamChecksParamValidation, getTeamChecksQueryValidation, + updateCheckStatusBodyValidation, deleteChecksParamValidation, deleteChecksByTeamIdParamValidation, updateChecksTTLBodyValidation, From a9c1d131a5c417d2d1eef9462f3b7623769ed6ce Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Fri, 20 Jun 2025 16:11:22 +0530 Subject: [PATCH 03/32] Route Update All Monitor/Team Checks --- server/controllers/checkController.js | 30 ++++++++++++++++++++++++++ server/db/mongo/modules/checkModule.js | 24 +++++++++++++++++++++ server/routes/checkRoute.js | 2 ++ server/validation/joi.js | 12 +++++++++++ 4 files changed, 68 insertions(+) diff --git a/server/controllers/checkController.js b/server/controllers/checkController.js index 0dece0a6d..230d58d0a 100755 --- a/server/controllers/checkController.js +++ b/server/controllers/checkController.js @@ -9,6 +9,8 @@ import { deleteChecksByTeamIdParamValidation, updateChecksTTLBodyValidation, updateCheckStatusBodyValidation, + updateAllChecksStatusBodyValidation, + updateCheckStatusParamValidation, } from "../validation/joi.js"; import jwt from "jsonwebtoken"; import { getTokenFromHeaders } from "../utils/utils.js"; @@ -130,6 +132,34 @@ class CheckController { } }; + updateAllChecksStatus = async (req, res, next) => { + try { + await updateCheckStatusParamValidation.validateAsync(req.params); + await updateAllChecksStatusBodyValidation.validateAsync(req.body); + } catch (error) { + next(handleValidationError(error, SERVICE_NAME)); + return; + } + + try { + const { monitorId, teamId, target } = req.params; + const { status } = req.body; + + const updatedChecks = await this.db.updateAllChecksStatus( + target === "monitor" ? monitorId : teamId, + status, + target + ); + + return res.success({ + msg: this.stringService.checkUpdateStatus, + data: updatedChecks, + }); + } catch (error) { + next(handleError(error, SERVICE_NAME, "updateAllChecksStatus")); + } + }; + deleteChecks = async (req, res, next) => { try { await deleteChecksParamValidation.validateAsync(req.params); diff --git a/server/db/mongo/modules/checkModule.js b/server/db/mongo/modules/checkModule.js index 97f088953..9cae8ed68 100755 --- a/server/db/mongo/modules/checkModule.js +++ b/server/db/mongo/modules/checkModule.js @@ -261,6 +261,29 @@ const updateCheckStatus = async (checkId, status) => { } }; +/** + * Update the status of all checks for a monitor or team + * @async + * @param {string} id + * @param {boolean} status + * @param {string} target + * @returns {Promise} + * @throws {Error} + */ +const updateAllChecksStatus = async (id, status, target) => { + try { + const updatedChecks = await Check.updateMany( + target === "monitor" ? { monitorId: id } : { teamId: id }, + { $set: { status: true } } + ); + return updatedChecks.modifiedCount; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "updateAllChecksStatus"; + throw error; + } +}; + /** * Delete all checks for a monitor * @async @@ -343,6 +366,7 @@ export { getChecksByMonitor, getChecksByTeam, updateCheckStatus, + updateAllChecksStatus, deleteChecks, deleteChecksByTeamId, updateChecksTTL, diff --git a/server/routes/checkRoute.js b/server/routes/checkRoute.js index d2b0590a0..c6d0c584f 100755 --- a/server/routes/checkRoute.js +++ b/server/routes/checkRoute.js @@ -22,6 +22,8 @@ class CheckRoutes { this.router.put("/:checkId", this.checkController.updateCheckStatus); + this.router.put("/:monitorId/:target", this.checkController.updateAllChecksStatus); + this.router.post( "/:monitorId", verifyOwnership(Monitor, "monitorId"), diff --git a/server/validation/joi.js b/server/validation/joi.js index 3c893260d..f8e57dc58 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -293,6 +293,16 @@ const updateCheckStatusBodyValidation = joi.object({ status: joi.boolean(), }); +const updateCheckStatusParamValidation = joi.object({ + monitorId: joi.string(), + teamId: joi.string(), + target: joi.string().allow("monitor", "team"), +}); + +const updateAllChecksStatusBodyValidation = joi.object({ + status: joi.boolean(), +}); + const getChecksParamValidation = joi.object({ monitorId: joi.string().required(), }); @@ -667,6 +677,8 @@ export { getTeamChecksParamValidation, getTeamChecksQueryValidation, updateCheckStatusBodyValidation, + updateAllChecksStatusBodyValidation, + updateCheckStatusParamValidation, deleteChecksParamValidation, deleteChecksByTeamIdParamValidation, updateChecksTTLBodyValidation, From faa2a2d965edf452fd0e129f346b779c82e5b9f7 Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Fri, 20 Jun 2025 20:42:57 +0530 Subject: [PATCH 04/32] Fixes in the controllers --- server/controllers/checkController.js | 4 ++-- server/db/mongo/modules/checkModule.js | 4 ++-- server/validation/joi.js | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/server/controllers/checkController.js b/server/controllers/checkController.js index 230d58d0a..15f889591 100755 --- a/server/controllers/checkController.js +++ b/server/controllers/checkController.js @@ -142,11 +142,11 @@ class CheckController { } try { - const { monitorId, teamId, target } = req.params; + const { monitorId, target } = req.params; const { status } = req.body; const updatedChecks = await this.db.updateAllChecksStatus( - target === "monitor" ? monitorId : teamId, + monitorId, status, target ); diff --git a/server/db/mongo/modules/checkModule.js b/server/db/mongo/modules/checkModule.js index 9cae8ed68..6c64756ee 100755 --- a/server/db/mongo/modules/checkModule.js +++ b/server/db/mongo/modules/checkModule.js @@ -159,7 +159,7 @@ const getChecksByTeam = async ({ status, }) => { try { - status = status === "true" ? true : false; + status = status === "true"; page = parseInt(page); rowsPerPage = parseInt(rowsPerPage); const matchStage = { @@ -274,7 +274,7 @@ const updateAllChecksStatus = async (id, status, target) => { try { const updatedChecks = await Check.updateMany( target === "monitor" ? { monitorId: id } : { teamId: id }, - { $set: { status: true } } + { $set: { status } } ); return updatedChecks.modifiedCount; } catch (error) { diff --git a/server/validation/joi.js b/server/validation/joi.js index f8e57dc58..4562e303e 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -295,7 +295,6 @@ const updateCheckStatusBodyValidation = joi.object({ const updateCheckStatusParamValidation = joi.object({ monitorId: joi.string(), - teamId: joi.string(), target: joi.string().allow("monitor", "team"), }); From 30d85e5712ffa17a688a5b1081d3b523a52fb597 Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Mon, 23 Jun 2025 22:07:03 +0530 Subject: [PATCH 05/32] Ack Field in Checks --- .../Components/IncidentTable/index.jsx | 6 ++--- client/src/Utils/NetworkService.js | 2 +- server/controllers/checkController.js | 12 +++------ server/db/models/Check.js | 17 ++++++++++++ server/db/mongo/modules/checkModule.js | 27 +++++++++++-------- server/validation/joi.js | 4 +-- 6 files changed, 42 insertions(+), 26 deletions(-) diff --git a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx index b4bfbe9dc..175649961 100644 --- a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx +++ b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx @@ -32,13 +32,11 @@ const IncidentTable = ({ const selectedMonitorDetails = monitors?.[selectedMonitor]; const selectedMonitorType = selectedMonitorDetails?.type; - const status = filter === "resolved" ? true : false; - const [checksMonitor, checksCountMonitor, isLoadingMonitor, networkErrorMonitor] = useFetchChecksByMonitor({ monitorId: selectedMonitor === "0" ? undefined : selectedMonitor, type: selectedMonitorType, - status: status, + status: false, sortOrder: "desc", limit: null, dateRange, @@ -50,7 +48,7 @@ const IncidentTable = ({ const [checksTeam, checksCountTeam, isLoadingTeam, networkErrorTeam] = useFetchChecksTeam({ - status: status, + status: false, sortOrder: "desc", limit: null, dateRange, diff --git a/client/src/Utils/NetworkService.js b/client/src/Utils/NetworkService.js index 8625b69e3..f953fc143 100644 --- a/client/src/Utils/NetworkService.js +++ b/client/src/Utils/NetworkService.js @@ -612,7 +612,7 @@ class NetworkService { */ async updateCheckStatus(config) { return this.axiosInstance.put(`/checks/${config.checkId}`, { - status: config.status, + ack: config.ack, }); } diff --git a/server/controllers/checkController.js b/server/controllers/checkController.js index 15f889591..e3d3436e2 100755 --- a/server/controllers/checkController.js +++ b/server/controllers/checkController.js @@ -119,9 +119,9 @@ class CheckController { try { const { checkId } = req.params; - const { status } = req.body; + const { ack } = req.body; - const updatedCheck = await this.db.updateCheckStatus(checkId, status); + const updatedCheck = await this.db.updateCheckStatus(checkId, ack); return res.success({ msg: this.stringService.checkUpdateStatus, @@ -143,13 +143,9 @@ class CheckController { try { const { monitorId, target } = req.params; - const { status } = req.body; + const { ack } = req.body; - const updatedChecks = await this.db.updateAllChecksStatus( - monitorId, - status, - target - ); + const updatedChecks = await this.db.updateAllChecksStatus(monitorId, ack, target); return res.success({ msg: this.stringService.checkUpdateStatus, diff --git a/server/db/models/Check.js b/server/db/models/Check.js index 39c5281d2..8bb6cd028 100755 --- a/server/db/models/Check.js +++ b/server/db/models/Check.js @@ -64,6 +64,23 @@ const BaseCheckSchema = mongoose.Schema({ default: Date.now, expires: 60 * 60 * 24 * 30, // 30 days }, + /** + * Acknowledgment of the check. + * + * @type {Boolean} + */ + ack: { + type: Boolean, + default: false, + }, + /** + * Resolution date of the check (when the check was resolved). + * + * @type {Date} + */ + ackAt: { + type: Date, + }, }); /** diff --git a/server/db/mongo/modules/checkModule.js b/server/db/mongo/modules/checkModule.js index 6c64756ee..0a4b1ad63 100755 --- a/server/db/mongo/modules/checkModule.js +++ b/server/db/mongo/modules/checkModule.js @@ -239,20 +239,25 @@ const getChecksByTeam = async ({ }; /** - * Update the status of a check + * Update the acknowledgment status of a check * @async - * @param {string} checkId - * @param {boolean} status + * @param {string} checkId - The ID of the check to update + * @param {boolean} ack - The acknowledgment status to set * @returns {Promise} * @throws {Error} */ -const updateCheckStatus = async (checkId, status) => { +const updateCheckStatus = async (checkId, ack) => { try { const updatedCheck = await Check.findOneAndUpdate( { _id: checkId }, - { status }, + { $set: { ack, ackAt: new Date() } }, { new: true } ); + + if (!updatedCheck) { + throw new Error("Check not found"); + } + return updatedCheck; } catch (error) { error.service = SERVICE_NAME; @@ -262,19 +267,19 @@ const updateCheckStatus = async (checkId, status) => { }; /** - * Update the status of all checks for a monitor or team + * Update the acknowledgment status of all checks for a monitor or team * @async - * @param {string} id - * @param {boolean} status - * @param {string} target + * @param {string} id - The monitor ID or team ID + * @param {boolean} ack - The acknowledgment status to set + * @param {string} target - The target type ('monitor' or 'team') * @returns {Promise} * @throws {Error} */ -const updateAllChecksStatus = async (id, status, target) => { +const updateAllChecksStatus = async (id, ack, target) => { try { const updatedChecks = await Check.updateMany( target === "monitor" ? { monitorId: id } : { teamId: id }, - { $set: { status } } + { $set: { ack, ackAt: new Date() } } ); return updatedChecks.modifiedCount; } catch (error) { diff --git a/server/validation/joi.js b/server/validation/joi.js index 4562e303e..ff1fa65c5 100755 --- a/server/validation/joi.js +++ b/server/validation/joi.js @@ -290,7 +290,7 @@ const createCheckBodyValidation = joi.object({ }); const updateCheckStatusBodyValidation = joi.object({ - status: joi.boolean(), + ack: joi.boolean(), }); const updateCheckStatusParamValidation = joi.object({ @@ -299,7 +299,7 @@ const updateCheckStatusParamValidation = joi.object({ }); const updateAllChecksStatusBodyValidation = joi.object({ - status: joi.boolean(), + ack: joi.boolean(), }); const getChecksParamValidation = joi.object({ From 40f4294caebbfcaca78271525aaefa12177ad618 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Jun 2025 12:07:02 +0800 Subject: [PATCH 06/32] cascade on superuser delete --- server/controllers/authController.js | 7 ------- server/db/models/User.js | 21 +++++++++++++++++++++ server/service/stringService.js | 4 ++++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/server/controllers/authController.js b/server/controllers/authController.js index d517c50d9..1d8c2af0e 100755 --- a/server/controllers/authController.js +++ b/server/controllers/authController.js @@ -423,13 +423,6 @@ class AuthController { await this.jobQueue.deleteJob(monitor); }) )); - - // 3. Delete team - await this.db.deleteTeam(user.teamId); - // 4. Delete all other team members - await this.db.deleteAllOtherUsers(); - // 5. Delete each monitor - await this.db.deleteMonitorsByUserId(user._id); } // 6. Delete the user by id await this.db.deleteUser(user._id); diff --git a/server/db/models/User.js b/server/db/models/User.js index 74ee1166e..d978f659b 100755 --- a/server/db/models/User.js +++ b/server/db/models/User.js @@ -1,6 +1,9 @@ import mongoose from "mongoose"; import bcrypt from "bcryptjs"; import logger from "../../utils/logger.js"; +import Monitor from "./Monitor.js"; +import Team from "./Team.js"; +import Notification from "./Notification.js"; const UserSchema = mongoose.Schema( { @@ -74,6 +77,24 @@ UserSchema.pre("findOneAndUpdate", function (next) { next(); }); +UserSchema.pre("findOneAndDelete", async function (next) { + try { + const userToDelete = await this.model.findOne(this.getFilter()); + if (userToDelete.role.includes("superadmin")) { + await Team.deleteOne({ _id: userToDelete.teamId }); + await Monitor.deleteMany({ userId: userToDelete._id }); + await this.model.deleteMany({ + teamId: userToDelete.teamId, + _id: { $ne: userToDelete._id }, + }); + await Notification.deleteMany({ teamId: userToDelete.teamId }); + } + next(); + } catch (error) { + next(error); + } +}); + UserSchema.methods.comparePassword = async function (submittedPassword) { const res = await bcrypt.compare(submittedPassword, this.password); return res; diff --git a/server/service/stringService.js b/server/service/stringService.js index 5ee17a5ef..6f9ad8cd8 100755 --- a/server/service/stringService.js +++ b/server/service/stringService.js @@ -444,6 +444,10 @@ class StringService { get verifyOwnerUnauthorized() { return this.translationService.getTranslation("verifyOwnerUnauthorized"); } + + get dbUserNotFound() { + return this.translationService.getTranslation("dbUserNotFound"); + } } export default StringService; From c16d5c424667b04658b5d74aaa381b357ace88d3 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Jun 2025 13:25:10 +0800 Subject: [PATCH 07/32] early return if user not found --- server/db/models/User.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/db/models/User.js b/server/db/models/User.js index d978f659b..f180cfb86 100755 --- a/server/db/models/User.js +++ b/server/db/models/User.js @@ -80,6 +80,7 @@ UserSchema.pre("findOneAndUpdate", function (next) { UserSchema.pre("findOneAndDelete", async function (next) { try { const userToDelete = await this.model.findOne(this.getFilter()); + if (!userToDelete) return next(); if (userToDelete.role.includes("superadmin")) { await Team.deleteOne({ _id: userToDelete.teamId }); await Monitor.deleteMany({ userId: userToDelete._id }); From 4d913772590934621c9a1db6cc3f704ed11f3f9a Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Jun 2025 14:30:14 +0800 Subject: [PATCH 08/32] fix settings page strings --- client/src/Pages/Settings/SettingsAbout.jsx | 4 +- .../Pages/Settings/SettingsDemoMonitors.jsx | 20 +- client/src/Pages/Settings/SettingsEmail.jsx | 58 +- .../src/Pages/Settings/SettingsPagespeed.jsx | 12 +- client/src/Pages/Settings/SettingsStats.jsx | 22 +- .../src/Pages/Settings/SettingsTimeZone.jsx | 9 +- client/src/Pages/Settings/SettingsUI.jsx | 10 +- client/src/Pages/Settings/SettingsURL.jsx | 12 +- client/src/Pages/Settings/index.jsx | 4 +- client/src/Utils/Theme/globalTheme.js | 5 + client/src/locales/en.json | 1514 +++++++++-------- 11 files changed, 861 insertions(+), 809 deletions(-) diff --git a/client/src/Pages/Settings/SettingsAbout.jsx b/client/src/Pages/Settings/SettingsAbout.jsx index 6acadd444..861d2f30c 100644 --- a/client/src/Pages/Settings/SettingsAbout.jsx +++ b/client/src/Pages/Settings/SettingsAbout.jsx @@ -16,7 +16,7 @@ const SettingsAbout = () => { component="h1" variant="h2" > - {t("settingsAbout")} + {t("settingsPage.aboutSettings.title")} @@ -24,7 +24,7 @@ const SettingsAbout = () => { {t("common.appName")} {2.1} - {t("settingsDevelopedBy")} + {t("settingsPage.aboutSettings.labelDevelopedBy")} - {t("settingsDemoMonitors")} + {t("settingsPage.demoMonitorsSettings.title")} + + + {t("settingsPage.demoMonitorsSettings.description")} - {t("settingsDemoMonitorsDescription")} - {t("settingsAddDemoMonitors")} @@ -57,14 +58,13 @@ const SettingsDemoMonitors = ({ isAdmin, HEADER_SX, handleChange, isLoading }) = component="h1" variant="h2" > - {t("settingsSystemReset")} + {t("settingsPage.systemResetSettings.title")} - {t("settingsSystemResetDescription")} + {t("settingsPage.systemResetSettings.description")} - {t("settingsRemoveAllMonitors")} setIsOpen(false)} - confirmationButtonLabel={t("settingsRemoveAllMonitorsDialogConfirm")} + confirmationButtonLabel={t("settingsPage.systemResetSettings.dialogConfirm")} onConfirm={() => { const syntheticEvent = { target: { diff --git a/client/src/Pages/Settings/SettingsEmail.jsx b/client/src/Pages/Settings/SettingsEmail.jsx index 1ae4a1f02..6c527eaec 100644 --- a/client/src/Pages/Settings/SettingsEmail.jsx +++ b/client/src/Pages/Settings/SettingsEmail.jsx @@ -9,7 +9,7 @@ import TextLink from "../../Components/TextLink"; // Utils import { useTheme } from "@emotion/react"; import { PropTypes } from "prop-types"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments"; import { useSendTestEmail } from "../../Hooks/useSendTestEmail"; @@ -111,14 +111,16 @@ const SettingsEmail = ({ component="h1" variant="h2" > - {t("settingsEmail")} + {t("settingsPage.emailSettings.title")} + + + {t("settingsPage.emailSettings.description")} - {t("settingsEmailDescription")} - {t("settingsEmailHost")} + {t("settingsPage.emailSettings.labelHost")} - {t("settingsEmailPort")} + {t("settingsPage.emailSettings.labelPort")} - {t("settingsEmailUser")} + {t("settingsPage.emailSettings.labelUser")} - {t("settingsEmailAddress")} + {t("settingsPage.emailSettings.labelAddress")} {(isEmailPasswordSet === false || emailPasswordHasBeenReset === true) && ( - {t("settingsEmailPassword")} + {t("settingsPage.emailSettings.labelPassword")} - {t("settingsEmailFieldResetLabel")} + {t("settingsPage.emailSettings.labelPasswordSet")} )} diff --git a/client/src/Pages/Settings/SettingsPagespeed.jsx b/client/src/Pages/Settings/SettingsPagespeed.jsx index 7d7cf0216..e9eff79b5 100644 --- a/client/src/Pages/Settings/SettingsPagespeed.jsx +++ b/client/src/Pages/Settings/SettingsPagespeed.jsx @@ -8,7 +8,7 @@ import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornmen // Utils import { useTheme } from "@emotion/react"; import { PropTypes } from "prop-types"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; const SettingsPagespeed = ({ @@ -46,15 +46,17 @@ const SettingsPagespeed = ({ component="h1" variant="h2" > - {t("pageSpeedApiKeyFieldTitle")} + {t("settingsPage.pageSpeedSettings.title")} + + + {t("settingsPage.pageSpeedSettings.description")} - {t("pageSpeedApiKeyFieldDescription")} {(isApiKeySet === false || apiKeyHasBeenReset === true) && ( - {t("pageSpeedApiKeyFieldResetLabel")} + {t("settingsPage.pageSpeedSettings.labelAPiKeySet")} setIsOpen(false)} - confirmationButtonLabel={t("settingsClearAllStatsDialogConfirm")} + confirmationButtonLabel={t( + "settingsPage.statsSettings.clearAllStatsDialogConfirm" + )} onConfirm={() => { const syntheticEvent = { target: { diff --git a/client/src/Pages/Settings/SettingsTimeZone.jsx b/client/src/Pages/Settings/SettingsTimeZone.jsx index 86fc72992..346e4e546 100644 --- a/client/src/Pages/Settings/SettingsTimeZone.jsx +++ b/client/src/Pages/Settings/SettingsTimeZone.jsx @@ -19,16 +19,17 @@ const SettingsTimeZone = ({ HEADING_SX, handleChange, timezone }) => { component="h1" variant="h2" > - {t("settingsGeneralSettings")} + {t("settingsPage.timezoneSettings.title")} - {t("settingsDisplayTimezone")}-{" "} - {t("settingsDisplayTimezoneDescription")} + + {t("settingsPage.timezoneSettings.description")} + { > diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index 0cd954e52..dae6bd680 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -157,7 +157,7 @@ const Settings = () => { return ( - Settings + {t("settingsPage.title")} { sx={{ px: theme.spacing(12), py: theme.spacing(8) }} onClick={handleSave} > - {t("settingsSave")} + {t("settingsPage.saveButtonLabel")} diff --git a/client/src/Utils/Theme/globalTheme.js b/client/src/Utils/Theme/globalTheme.js index ae014432d..eb827a907 100644 --- a/client/src/Utils/Theme/globalTheme.js +++ b/client/src/Utils/Theme/globalTheme.js @@ -36,6 +36,11 @@ const baseTheme = (palette) => ({ color: palette.primary.contrastTextTertiary, fontWeight: 400, }, + label: { + fontSize: "var(--env-var-font-size-medium)", + color: palette.primary.contrastTextSecondary, + fontWeight: 500, + }, }, /* TODO change to 4 */ spacing: 2, diff --git a/client/src/locales/en.json b/client/src/locales/en.json index b57bb1e15..72dda4c64 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -1,594 +1,29 @@ { - "submit": "Submit", - "title": "Title", - "distributedStatusHeaderText": "Real-time, real-device coverage", - "distributedStatusSubHeaderText": "Powered by millions devices worldwide, view a system performance by global region, country or city", - "settingsGeneralSettings": "General settings", - "settingsDisplayTimezone": "Display timezone", - "settingsDisplayTimezoneDescription": "Select the timezone used to display dates and times throughout the application.", - "settingsAppearance": "Appearance", - "settingsAppearanceDescription": "Switch between light and dark mode, or change user interface language", - "settingsThemeMode": "Theme Mode", - "settingsLanguage": "Language", - "settingsEnabled": "Enabled", - "settingsDisabled": "Disabled", - "settingsHistoryAndMonitoring": "History of monitoring", - "settingsHistoryAndMonitoringDescription": "Define how long you want to retain historical data. You can also clear all existing data.", - "settingsTTLLabel": "The days you want to keep monitoring history.", - "settingsTTLOptionalLabel": "0 for infinite", - "settingsClearAllStats": "Clear all stats. This is irreversible.", - "settingsClearAllStatsButton": "Clear all stats", - "settingsClearAllStatsDialogTitle": "Do you want to clear all stats?", - "settingsClearAllStatsDialogDescription": "Once removed, the monitoring history and stats cannot be retrieved.", - "settingsClearAllStatsDialogConfirm": "Yes, clear all stats", - "settingsDemoMonitors": "Demo monitors", - "settingsDemoMonitorsDescription": "Add sample monitors for demonstration purposes.", - "settingsAddDemoMonitors": "Adding demo monitors", - "settingsAddDemoMonitorsButton": "Add demo monitors", - "settingsRemoveAllMonitors": "Removing all monitors", - "settingsRemoveAllMonitorsButton": "Remove all monitors", - "settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?", - "settingsRemoveAllMonitorsDialogConfirm": "Yes, remove all monitors", - "settingsAbout": "About", - "settingsDevelopedBy": "Developed by Bluewave Labs.", - "settingsSave": "Save", - "settingsSuccessSaved": "Settings saved successfully", - "settingsFailedToSave": "Failed to save settings", - "settingsStatsCleared": "Stats cleared successfully", - "settingsFailedToClearStats": "Failed to clear stats", - "settingsDemoMonitorsAdded": "Successfully added demo monitors", - "settingsFailedToAddDemoMonitors": "Failed to add demo monitors", - "settingsMonitorsDeleted": "Successfully deleted all monitors", - "settingsFailedToDeleteMonitors": "Failed to delete all monitors", - "starPromptTitle": "Star Checkmate", - "starPromptDescription": "See the latest releases and help grow the community on GitHub", - "https": "HTTPS", - "http": "HTTP", - "monitor": "monitor", - "aboutus": "About Us", - "now": "Now", - "delete": "Delete", - "configure": "Configure", - "responseTime": "Response time", - "ms": "ms", - "bar": "Bar", - "area": "Area", - "country": "COUNTRY", - "city": "CITY", - "response": "RESPONSE", - "monitorStatusUp": "Monitor {name} ({url}) is now UP and responding", - "monitorStatusDown": "Monitor {name} ({url}) is DOWN and not responding", - "webhookSendSuccess": "Webhook notification sent successfully", - "webhookSendError": "Error sending webhook notification to {platform}", - "webhookUnsupportedPlatform": "Unsupported platform: {platform}", - "distributedRightCategoryTitle": "Monitor", - "distributedStatusServerMonitors": "Server Monitors", - "distributedStatusServerMonitorsDescription": "Monitor status of related servers", - "distributedUptimeCreateSelectURL": "Here you can select the URL of the host, together with the type of monitor.", - "distributedUptimeCreateChecks": "Checks to perform", - "distributedUptimeCreateChecksDescription": "You can always add or remove checks after adding your site.", - "distributedUptimeCreateIncidentNotification": "Incident notifications", - "distributedUptimeCreateIncidentDescription": "When there is an incident, notify users.", - "distributedUptimeCreateAdvancedSettings": "Advanced settings", - "distributedUptimeDetailsNoMonitorHistory": "There is no check history for this monitor yet.", - "distributedUptimeDetailsStatusHeaderUptime": "Uptime:", - "distributedUptimeDetailsStatusHeaderLastUpdate": "Last updated", - "notifications": { - "enableNotifications": "Enable {{platform}} notifications", - "testNotification": "Test notification", - "addOrEditNotifications": "Add or edit notifications", - "slack": { - "label": "Slack", - "description": "To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.", - "webhookLabel": "Webhook URL", - "webhookPlaceholder": "https://hooks.slack.com/services/...", - "webhookRequired": "Slack webhook URL is required" - }, - "discord": { - "label": "Discord", - "description": "To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature.", - "webhookLabel": "Discord Webhook URL", - "webhookPlaceholder": "https://discord.com/api/webhooks/...", - "webhookRequired": "Discord webhook URL is required" - }, - "telegram": { - "label": "Telegram", - "description": "To enable Telegram notifications, create a Telegram bot using BotFather, an official bot for creating and managing Telegram bots. Then, get the API token and chat ID and write them down here.", - "tokenLabel": "Your bot token", - "tokenPlaceholder": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11", - "chatIdLabel": "Your Chat ID", - "chatIdPlaceholder": "-1001234567890", - "fieldsRequired": "Telegram token and chat ID are required" - }, - "webhook": { - "label": "Webhooks", - "description": "You can set up a custom webhook to receive notifications when incidents occur.", - "urlLabel": "Webhook URL", - "urlPlaceholder": "https://your-server.com/webhook", - "urlRequired": "Webhook URL is required" - }, - "testNotificationDevelop": "Test notification 2", - "integrationButton": "Notification Integration", - "testSuccess": "Test notification sent successfully!", - "testFailed": "Failed to send test notification", - "unsupportedType": "Unsupported notification type", - "networkError": "Network error occurred", - "fallback": { - "title": "notification channel", - "checks": [ - "Alert teams about downtime or performance issues", - "Let engineers know when incidents happen", - "Keep administrators informed of system changes" - ] - }, - "createButton": "Create notification channel", - "createTitle": "Notification channel", - "create": { - "success": "Notification created successfully", - "failed": "Failed to create notification" - }, - "fetch": { - "success": "Notifications fetched successfully", - "failed": "Failed to fetch notifications" - }, - "delete": { - "success": "Notification deleted successfully", - "failed": "Failed to delete notification" - }, - "edit": { - "success": "Notification updated successfully", - "failed": "Failed to update notification" - }, - "test": { - "success": "Test notification sent successfully", - "failed": "Failed to send test notification" - } - }, - "testLocale": "testLocale", - "add": "Add", - "monitors": "monitors", - "distributedUptimeStatusCreateStatusPage": "status page", - "distributedUptimeStatusCreateStatusPageAccess": "Access", - "distributedUptimeStatusCreateStatusPageReady": "If your status page is ready, you can mark it as published.", - "distributedUptimeStatusBasicInfoHeader": "Basic Information", - "distributedUptimeStatusBasicInfoDescription": "Define company name and the subdomain that your status page points to.", - "distributedUptimeStatusLogoHeader": "Logo", - "distributedUptimeStatusLogoDescription": "Upload a logo for your status page", - "distributedUptimeStatusLogoUploadButton": "Upload logo", - "distributedUptimeStatusStandardMonitorsHeader": "Standard Monitors", - "distributedUptimeStatusStandardMonitorsDescription": "Attach standard monitors to your status page.", - "distributedUptimeStatusCreateYour": "Create your", - "distributedUptimeStatusEditYour": "Edit your", - "distributedUptimeStatusPublishedLabel": "Published and visible to the public", - "distributedUptimeStatusCompanyNameLabel": "Company name", - "distributedUptimeStatusPageAddressLabel": "Your status page address", - "distributedUptimeStatus30Days": "30 days", - "distributedUptimeStatus60Days": "60 days", - "distributedUptimeStatus90Days": "90 days", - "distributedUptimeStatusPageNotSetUp": "A status page is not set up.", - "distributedUptimeStatusContactAdmin": "Please contact your administrator", - "distributedUptimeStatusPageNotPublic": "This status page is not public.", - "distributedUptimeStatusPageDeleteDialog": "Do you want to delete this status page?", - "distributedUptimeStatusPageDeleteConfirm": "Yes, delete status page", - "distributedUptimeStatusPageDeleteDescription": "Once deleted, your status page cannot be retrieved.", - "distributedUptimeStatusDevices": "Devices", - "distributedUptimeStatusUpt": "UPT", - "distributedUptimeStatusUptBurned": "UPT Burned", - "distributedUptimeStatusUptLogo": "Upt Logo", - "incidentsTableNoIncidents": "No incidents recorded", - "incidentsTablePaginationLabel": "incidents", - "incidentsTableMonitorName": "Monitor Name", - "incidentsTableStatus": "Status", - "incidentsTableDateTime": "Date & Time", - "incidentsTableStatusCode": "Status Code", - "incidentsTableMessage": "Message", - "incidentsOptionsHeader": "Incidents for:", - "incidentsOptionsHeaderFilterBy": "Filter by:", - "incidentsOptionsHeaderFilterAll": "All", - "incidentsOptionsHeaderFilterDown": "Down", - "incidentsOptionsHeaderFilterCannotResolve": "Cannot resolve", - "incidentsOptionsHeaderShow": "Show:", - "incidentsOptionsHeaderLastHour": "Last hour", - "incidentsOptionsHeaderLastDay": "Last day", - "incidentsOptionsHeaderLastWeek": "Last week", - "incidentsOptionsPlaceholderAllServers": "All servers", - "infrastructureCreateYour": "Create your", - "infrastructureCreateGeneralSettingsDescription": "Here you can select the URL of the host, together with the friendly name and authorization secret to connect to the server agent.", - "infrastructureServerRequirement": "The server you are monitoring must be running the", - "infrastructureCustomizeAlerts": "Customize alerts", - "infrastructureAlertNotificationDescription": "Send a notification to user(s) when thresholds exceed a specified percentage.", - "infrastructureCreateMonitor": "Create Infrastructure Monitor", - "infrastructureProtocol": "Protocol", - "infrastructureServerUrlLabel": "Server URL", - "infrastructureDisplayNameLabel": "Display name", - "infrastructureAuthorizationSecretLabel": "Authorization secret", - "gb": "GB", - "mb": "MB", - "mem": "Mem", - "memoryUsage": "Memory usage", - "cpu": "CPU", - "cpuUsage": "CPU usage", - "cpuTemperature": "CPU Temperature", - "diskUsage": "Disk Usage", - "used": "Used", - "total": "Total", - "cores": "Cores", - "frequency": "Frequency", - "status": "Status", - "cpuPhysical": "CPU (Physical)", - "cpuLogical": "CPU (Logical)", - "cpuFrequency": "CPU Frequency", - "avgCpuTemperature": "Average CPU Temperature", - "memory": "Memory", - "disk": "Disk", - "uptime": "Uptime", - "os": "OS", - "host": "Host", - "actions": "Actions", - "integrations": "Integrations", - "integrationsPrism": "Connect Prism to your favorite service.", - "integrationsSlack": "Slack", - "integrationsSlackInfo": "Connect with Slack and see incidents in a channel", - "integrationsDiscord": "Discord", - "integrationsDiscordInfo": "Connect with Discord and view incidents directly in a channel", - "integrationsZapier": "Zapier", - "integrationsZapierInfo": "Send all incidents to Zapier, and then see them everywhere", - "commonSave": "Save", - "createYour": "Create your", - "createMonitor": "Create monitor", - "pause": "Pause", - "resume": "Resume", - "editing": "Editing...", - "url": "URL", - "access": "Access", - "timezone": "Timezone", - "features": "Features", - "administrator": "Administrator?", - "loginHere": "Login here", - "displayName": "Display name", - "urlMonitor": "URL to monitor", - "portToMonitor": "Port to monitor", - "websiteMonitoring": "Website monitoring", - "websiteMonitoringDescription": "Use HTTP(s) to monitor your website or API endpoint.", - "pingMonitoring": "Ping monitoring", - "pingMonitoringDescription": "Check whether your server is available or not.", - "dockerContainerMonitoring": "Docker container monitoring", - "dockerContainerMonitoringDescription": "Check whether your Docker container is running or not.", - "portMonitoring": "Port monitoring", - "portMonitoringDescription": "Check whether your port is open or not.", - "createMaintenanceWindow": "Create maintenance window", - "createMaintenance": "Create maintenance", - "editMaintenance": "Edit maintenance", - "maintenanceWindowName": "Maintenance Window Name", - "friendlyNameInput": "Friendly name", - "friendlyNamePlaceholder": "Maintenance at __ : __ for ___ minutes", - "maintenanceRepeat": "Maintenance Repeat", - "maintenance": "maintenance", - "duration": "Duration", - "addMonitors": "Add monitors", - "window": "window", - "cancel": "Cancel", - "message": "Message", - "low": "low", - "high": "high", - "statusCode": "Status code", - "date&Time": "Date & Time", - "type": "Type", - "statusPageName": "Status page name", - "publicURL": "Public URL", - "repeat": "Repeat", - "edit": "Edit", - "createA": "Create a", - "remove": "Remove", - "maintenanceWindowDescription": "Your pings won't be sent during this time frame", - "startTime": "Start time", - "timeZoneInfo": "All dates and times are in GMT+0 time zone.", - "monitorsToApply": "Monitors to apply maintenance window to", - "nextWindow": "Next window", - "notFoundButton": "Go to the main dashboard", - "pageSpeedConfigureSettingsDescription": "Here you can select the URL of the host, together with the type of monitor.", - "monitorDisplayName": "Monitor display name", - "whenNewIncident": "When there is a new incident,", - "notifySMS": "Notify via SMS (coming soon)", - "notifyEmails": "Also notify via email to multiple addresses (coming soon)", - "seperateEmails": "You can separate multiple emails with a comma", - "checkFrequency": "Check frequency", - "matchMethod": "Match Method", - "expectedValue": "Expected value", - "deleteDialogTitle": "Do you really want to delete this monitor?", - "deleteDialogDescription": "Once deleted, this monitor cannot be retrieved.", - "pageSpeedMonitor": "PageSpeed monitor", - "shown": "Shown", - "ago": "ago", - "companyName": "Company name", - "pageSpeedDetailsPerformanceReport": "Values are estimated and may vary.", - "pageSpeedDetailsPerformanceReportCalculator": "See calculator", - "checkingEvery": "Checking every", - "statusPageCreateSettings": "If your status page is ready, you can mark it as published.", - "basicInformation": "Basic Information", - "statusPageCreateBasicInfoDescription": "Define company name and the subdomain that your status page points to.", - "statusPageCreateSelectTimeZoneDescription": "Select the timezone that your status page will be displayed in.", - "statusPageCreateAppearanceDescription": "Define the default look and feel of your public status page.", - "statusPageCreateSettingsCheckboxLabel": "Published and visible to the public", - "statusPageCreateBasicInfoStatusPageAddress": "Your status page address", - "statusPageCreateTabsContent": "Status page servers", - "statusPageCreateTabsContentDescription": "You can add any number of servers that you monitor to your status page. You can also reorder them for the best viewing experience.", - "statusPageCreateTabsContentFeaturesDescription": "Show more details on the status page", - "showCharts": "Show charts", - "showUptimePercentage": "Show uptime percentage", - "showAdminLoginLink": "Show \"Administrator? Login Here\" link on the status page", - "removeLogo": "Remove Logo", - "statusPageStatus": "A public status page is not set up.", - "statusPageStatusContactAdmin": "Please contact to your administrator", - "statusPageStatusNotPublic": "This status page is not public.", - "statusPageStatusNoPage": "There's no status page here.", - "statusPageStatusServiceStatus": "Service status", - "deleteStatusPage": "Do you want to delete this status page?", - "deleteStatusPageConfirm": "Yes, delete status page", - "deleteStatusPageDescription": "Once deleted, your status page cannot be retrieved.", - "uptimeCreate": "The expected value is used to match against response result, and the match determines the status.", - "uptimeCreateJsonPath": "This expression will be evaluated against the reponse JSON data and the result will be used to match against the expected value. See", - "uptimeCreateJsonPathQuery": "for query language documentation.", - "maintenanceTableActionMenuDialogTitle": "Do you really want to remove this maintenance window?", - "infrastructureEditYour": "Edit your", - "infrastructureEditMonitor": "Save Infrastructure Monitor", - "infrastructureMonitorCreated": "Infrastructure monitor created successfully!", - "infrastructureMonitorUpdated": "Infrastructure monitor updated successfully!", - "errorInvalidTypeId": "Invalid notification type provided", - "errorInvalidFieldId": "Invalid field ID provided", - "inviteNoTokenFound": "No invite token found", - "pageSpeedWarning": "Warning: You haven't added a Google PageSpeed API key yet. Without it, the PageSpeed monitor won't function.", - "pageSpeedLearnMoreLink": "Click here", - "pageSpeedAddApiKey": "to add your API key.", - "update": "Update", - "invalidFileFormat": "Unsupported file format!", - "invalidFileSize": "File size is too large!", "ClickUpload": "Click to upload", + "DeleteAccountButton": "Remove account", + "DeleteAccountTitle": "Remove account", + "DeleteAccountWarning": "Removing your account means you won't be able to sign in again and all your data will be removed. This isn't reversible.", + "DeleteDescriptionText": "This will remove the account and all associated data from the server. This isn't reversible.", + "DeleteWarningTitle": "Really remove this account?", "DragandDrop": "drag and drop", - "MaxSize": "Maximum Size", - "SupportedFormats": "Supported formats", + "EmailDescriptionText": "This is your current email address — it cannot be changed.", "FirstName": "First name", "LastName": "Last name", - "EmailDescriptionText": "This is your current email address — it cannot be changed.", - "YourPhoto": "Profile photo", + "MaxSize": "Maximum Size", "PhotoDescriptionText": "This photo will be displayed in your profile page.", - "save": "Save", - "DeleteDescriptionText": "This will remove the account and all associated data from the server. This isn't reversible.", - "DeleteAccountWarning": "Removing your account means you won't be able to sign in again and all your data will be removed. This isn't reversible.", - "DeleteWarningTitle": "Really remove this account?", - "bulkImport": { - "title": "Bulk Import", - "selectFileTips": "Select CSV file to upload", - "selectFileDescription": "You can download our or sample", - "selectFile": "Select File", - "parsingFailed": "Parsing failed", - "uploadSuccess": "Monitors created successfully!", - "validationFailed": "Validation failed", - "noFileSelected": "No file selected", - "fallbackPage": "Import a file to upload a list of servers in bulk" - }, - "settingsSystemReset": "System reset", - "settingsSystemResetDescription": "Remove all monitors from your system.", - "DeleteAccountTitle": "Remove account", - "DeleteAccountButton": "Remove account", - "publicLink": "Public link", - "maskedPageSpeedKeyPlaceholder": "*************************************", - "pageSpeedApiKeyFieldTitle": "Google PageSpeed API key", - "pageSpeedApiKeyFieldLabel": "PageSpeed API key", - "pageSpeedApiKeyFieldDescription": "Enter your Google PageSpeed API key to enable pagespeed monitoring. Click Reset to update the key.", - "pageSpeedApiKeyFieldResetLabel": "API key is set. Click Reset to change it.", - "reset": "Reset", - "ignoreTLSError": "Ignore TLS/SSL error", - "tlsErrorIgnored": "TLS/SSL errors ignored", - "ignoreTLSErrorDescription": "Ignore TLS/SSL errors and continue checking the website's availability", - "createNew": "Create new", - "greeting": { - "prepend": "Hey there", - "append": "The afternoon is your playground—let's make it epic!", - "overview": "Here's an overview of your {{type}} monitors." - }, - "roles": { - "superAdmin": "Super admin", - "admin": "Admin", - "teamMember": "Team member", - "demoUser": "Demo user" - }, - "teamPanel": { - "teamMembers": "Team members", - "filter": { - "all": "All", - "member": "Member" - }, - "inviteTeamMember": "Invite a team member", - "inviteNewTeamMember": "Invite new team member", - "inviteDescription": "When you add a new team member, they will get access to all monitors.", - "email": "Email", - "selectRole": "Select role", - "inviteLink": "Invite link", - "cancel": "Cancel", - "noMembers": "There are no team members with this role", - "getToken": "Get token", - "emailToken": "E-mail token", - "table": { - "name": "Name", - "email": "Email", - "role": "Role", - "created": "Created" - } - }, - "monitorState": { - "paused": "Paused", - "resumed": "Resumed", - "active": "Active" - }, - "menu": { - "uptime": "Uptime", - "pagespeed": "Pagespeed", - "infrastructure": "Infrastructure", - "incidents": "Incidents", - "statusPages": "Status pages", - "maintenance": "Maintenance", - "integrations": "Integrations", - "logs": "Logs", - "settings": "Settings", - "support": "Support", - "discussions": "Discussions", - "docs": "Docs", - "changelog": "Changelog", - "profile": "Profile", - "password": "Password", - "team": "Team", - "logOut": "Log out", - "notifications": "Notifications" - }, - "settingsEmail": "Email", - "settingsEmailDescription": "Configure the email settings for your system. This is used to send notifications and alerts.", - "settingsEmailHost": "Email host - Hostname or IP address to connect to", - "settingsEmailPort": "Email port - Port to connect to", - "settingsEmailAddress": "Email address - Used for authentication", - "settingsEmailPassword": "Email password - Password for authentication", - "settingsEmailUser": "Email user - Username for authentication, overrides email address if specified", - "settingsEmailFieldResetLabel": "Password is set. Click Reset to change it.", - "settingsEmailTransportLinkDescription": "This builds an SMTP transport for NodeMailer", - "settingsEmailTransportLinkText": "See specifications here", - "state": "State", - "statusBreadCrumbsStatusPages": "Status Pages", - "statusBreadCrumbsDetails": "Details", - "settingsThemeModeLight": "Light", - "settingsThemeModeDark": "Dark", - "settingsClearAllStatsDialogCancel": "Cancel", - "commonSaving": "Saving...", - "navControls": "Controls", - "incidentsPageTitle": "Incidents", - "passwordPanel": { - "passwordChangedSuccess": "Your password was changed successfully.", - "passwordInputIncorrect": "Your password input was incorrect.", - "currentPassword": "Current password", - "enterCurrentPassword": "Enter your current password", - "newPassword": "New password", - "enterNewPassword": "Enter your new password", - "confirmNewPassword": "Confirm new password", - "passwordRequirements": "New password must contain at least 8 characters and must have at least one uppercase letter, one lowercase letter, one number and one special character.", - "saving": "Saving..." - }, - "settingsEmailConnectionHost": "Email connection host - Hostname to use in the HELO/EHLO greeting", - "emailSent": "Email sent successfully", - "failedToSendEmail": "Failed to send email", - "settingsTestEmail": "Send test e-mail", - "settingsTestEmailSuccess": "Test email sent successfully", - "settingsTestEmailFailed": "Failed to send test email", - "settingsTestEmailFailedWithReason": "Failed to send test email: {{reason}}", - "settingsTestEmailUnknownError": "Unknown error", - "settingsEmailRequiredFields": "Email address, host, port and password are required", - "statusMsg": { - "paused": "Monitoring is paused.", - "up": "Your site is up.", - "down": "Your site is down.", - "pending": "Pending..." - }, - "settingsURLTitle": "Monitor IP/URL on Status Page", - "settingsURLDescription": "Display the IP address or URL of monitor on the public Status page. If it's disabled, only the monitor name will be shown to protect sensitive information.", - "settingsURLSelectTitle": "Display IP/URL on status page", - "settingsURLEnabled": "Enabled", - "settingURLDisabled": "Disabled", - "uptimeGeneralInstructions": { - "http": "Enter the URL or IP to monitor (e.g., https://example.com/ or 192.168.1.100) and add a clear display name that appears on the dashboard.", - "ping": "Enter the IP address or hostname to ping (e.g., 192.168.1.100 or example.com) and add a clear display name that appears on the dashboard.", - "docker": "Enter the Docker ID of your container. Docker IDs must be the full 64 char Docker ID. You can run docker inspect to get the full container ID.", - "port": "Enter the URL or IP of the server, the port number and a clear display name that appears on the dashboard." - }, - "common": { - "appName": "Checkmate", - "monitoringAgentName": "Capture", - "buttons": { - "toggleTheme": "Toggles light & dark" - }, - "toasts": { - "networkError": "Network error", - "checkConnection": "Please check your connection", - "unknownError": "Unknown error" - } - }, + "SupportedFormats": "Supported formats", + "YourPhoto": "Profile photo", + "aboutus": "About Us", + "access": "Access", + "actions": "Actions", + "add": "Add", + "addMonitors": "Add monitors", + "administrator": "Administrator?", + "advancedMatching": "Advanced matching", + "ago": "ago", + "area": "Area", "auth": { "common": { - "navigation": { - "continue": "Continue", - "back": "Back" - }, - "inputs": { - "email": { - "label": "Email", - "placeholder": "jordan.ellis@domain.com", - "errors": { - "empty": "To continue, please enter your email address", - "invalid": "Please recheck validity of entered email address" - } - }, - "password": { - "label": "Password", - "rules": { - "length": { - "beginning": "Must be at least", - "highlighted": "8 characters long" - }, - "special": { - "beginning": "Must contain at least", - "highlighted": "one special character" - }, - "number": { - "beginning": "Must contain at least", - "highlighted": "one number" - }, - "uppercase": { - "beginning": "Must contain at least", - "highlighted": "one upper character" - }, - "lowercase": { - "beginning": "Must contain at least", - "highlighted": "one lower character" - }, - "match": { - "beginning": "Confirm password and password", - "highlighted": "must match" - } - }, - "errors": { - "empty": "Please enter your password", - "length": "Password must be at least 8 characters long", - "uppercase": "Password must contain at least 1 uppercase letter", - "lowercase": "Password must contain at least 1 lowercase letter", - "number": "Password must contain at least 1 number", - "special": "Password must contain at least 1 special character", - "incorrect": "The password you provided does not match our records" - } - }, - "passwordConfirm": { - "label": "Confirm password", - "placeholder": "Re-enter password to confirm", - "errors": { - "empty": "Please enter your password again for confirmation (helps with typos)", - "different": "Entered passwords don't match, so one of them is probably mistyped" - } - }, - "firstName": { - "label": "Name", - "placeholder": "Jordan", - "errors": { - "empty": "Please enter your name", - "length": "Name must be less than 50 characters", - "pattern": "Name must contain only letters, spaces, apostrophes, or hyphens" - } - }, - "lastName": { - "label": "Surname", - "placeholder": "Ellis", - "errors": { - "empty": "Please enter your surname", - "length": "Surname must be less than 50 characters", - "pattern": "Surname must contain only letters, spaces, apostrophes, or hyphens" - } - } - }, "errors": { "validation": "Error validating data." }, @@ -598,40 +33,139 @@ "incorrect": "The password you provided does not match our records" } } + }, + "inputs": { + "email": { + "errors": { + "empty": "To continue, please enter your email address", + "invalid": "Please recheck validity of entered email address" + }, + "label": "Email", + "placeholder": "jordan.ellis@domain.com" + }, + "firstName": { + "errors": { + "empty": "Please enter your name", + "length": "Name must be less than 50 characters", + "pattern": "Name must contain only letters, spaces, apostrophes, or hyphens" + }, + "label": "Name", + "placeholder": "Jordan" + }, + "lastName": { + "errors": { + "empty": "Please enter your surname", + "length": "Surname must be less than 50 characters", + "pattern": "Surname must contain only letters, spaces, apostrophes, or hyphens" + }, + "label": "Surname", + "placeholder": "Ellis" + }, + "password": { + "errors": { + "empty": "Please enter your password", + "incorrect": "The password you provided does not match our records", + "length": "Password must be at least 8 characters long", + "lowercase": "Password must contain at least 1 lowercase letter", + "number": "Password must contain at least 1 number", + "special": "Password must contain at least 1 special character", + "uppercase": "Password must contain at least 1 uppercase letter" + }, + "label": "Password", + "rules": { + "length": { + "beginning": "Must be at least", + "highlighted": "8 characters long" + }, + "lowercase": { + "beginning": "Must contain at least", + "highlighted": "one lower character" + }, + "match": { + "beginning": "Confirm password and password", + "highlighted": "must match" + }, + "number": { + "beginning": "Must contain at least", + "highlighted": "one number" + }, + "special": { + "beginning": "Must contain at least", + "highlighted": "one special character" + }, + "uppercase": { + "beginning": "Must contain at least", + "highlighted": "one upper character" + } + } + }, + "passwordConfirm": { + "errors": { + "different": "Entered passwords don't match, so one of them is probably mistyped", + "empty": "Please enter your password again for confirmation (helps with typos)" + }, + "label": "Confirm password", + "placeholder": "Re-enter password to confirm" + } + }, + "navigation": { + "back": "Back", + "continue": "Continue" + } + }, + "forgotPassword": { + "buttons": { + "openEmail": "Open email app", + "resetPassword": "Reset password" + }, + "heading": "Forgot password?", + "imageAlts": { + "email": "Email icon", + "lock": "Lock icon", + "passwordConfirm": "Password confirm icon", + "passwordKey": "Password key icon" + }, + "links": { + "login": "Go back to Log In", + "resend": "Didn't receive the email? Click to resend" + }, + "subheadings": { + "stepFour": "Your password has been successfully reset. Click below to log in magically.", + "stepOne": "No worries, we'll send you reset instructions.", + "stepThree": "Your new password must be different from previously used passwords.", + "stepTwo": "We sent a password reset link to " + }, + "toasts": { + "emailNotFound": "Email not found.", + "error": "Unable to reset password. Please try again later or contact support.", + "redirect": "Redirecting in ...", + "sent": "Instructions sent to .", + "success": "Your password was reset successfully." } }, "login": { - "heading": "Log In", - "subheadings": { - "stepOne": "Enter your email", - "stepTwo": "Enter your password" - }, - "links": { - "forgotPassword": "Forgot password?", - "register": "Do not have an account?", - "forgotPasswordLink": "Reset password", - "registerLink": "Register here" - }, - "toasts": { - "success": "Welcome back! You're successfully logged in.", - "incorrectPassword": "Incorrect password" - }, "errors": { "password": { "incorrect": "The password you provided does not match our records" } + }, + "heading": "Log In", + "links": { + "forgotPassword": "Forgot password?", + "forgotPasswordLink": "Reset password", + "register": "Do not have an account?", + "registerLink": "Register here" + }, + "subheadings": { + "stepOne": "Enter your email", + "stepTwo": "Enter your password" + }, + "toasts": { + "incorrectPassword": "Incorrect password", + "success": "Welcome back! You're successfully logged in." } }, "registration": { - "heading": { - "superAdmin": "Create super admin", - "user": "Sign Up" - }, - "subheadings": { - "stepOne": "Enter your personal details", - "stepTwo": "Enter your email", - "stepThree": "Create your password" - }, "description": { "superAdmin": "Create your super admin account to get started", "user": "Sign up as a user and ask super admin for access to your monitors" @@ -640,183 +174,667 @@ "superAdmin": "Create super admin account", "user": "Sign up regular user" }, - "termsAndPolicies": "By creating an account, you agree to our Terms of Service and Privacy Policy.", + "heading": { + "superAdmin": "Create super admin", + "user": "Sign Up" + }, "links": { "login": "Already have an account? Log In" }, + "subheadings": { + "stepOne": "Enter your personal details", + "stepThree": "Create your password", + "stepTwo": "Enter your email" + }, + "termsAndPolicies": "By creating an account, you agree to our Terms of Service and Privacy Policy.", "toasts": { "success": "Welcome! Your account was created successfully." } - }, - "forgotPassword": { - "heading": "Forgot password?", - "subheadings": { - "stepOne": "No worries, we'll send you reset instructions.", - "stepTwo": "We sent a password reset link to ", - "stepThree": "Your new password must be different from previously used passwords.", - "stepFour": "Your password has been successfully reset. Click below to log in magically." - }, - "buttons": { - "openEmail": "Open email app", - "resetPassword": "Reset password" - }, - "imageAlts": { - "passwordKey": "Password key icon", - "email": "Email icon", - "lock": "Lock icon", - "passwordConfirm": "Password confirm icon" - }, - "links": { - "login": "Go back to Log In", - "resend": "Didn't receive the email? Click to resend" - }, - "toasts": { - "sent": "Instructions sent to .", - "emailNotFound": "Email not found.", - "redirect": "Redirecting in ...", - "success": "Your password was reset successfully.", - "error": "Unable to reset password. Please try again later or contact support." - } } }, + "avgCpuTemperature": "Average CPU Temperature", + "bar": "Bar", + "basicInformation": "Basic Information", + "bulkImport": { + "fallbackPage": "Import a file to upload a list of servers in bulk", + "noFileSelected": "No file selected", + "parsingFailed": "Parsing failed", + "selectFile": "Select File", + "selectFileDescription": "You can download our or sample", + "selectFileTips": "Select CSV file to upload", + "title": "Bulk Import", + "uploadSuccess": "Monitors created successfully!", + "validationFailed": "Validation failed" + }, + "cancel": "Cancel", + "checkFrequency": "Check frequency", + "checkingEvery": "Checking every", + "city": "CITY", + "common": { + "appName": "Checkmate", + "buttons": { + "toggleTheme": "Toggles light & dark" + }, + "monitoringAgentName": "Capture", + "toasts": { + "checkConnection": "Please check your connection", + "networkError": "Network error", + "unknownError": "Unknown error" + } + }, + "commonSave": "Save", + "commonSaving": "Saving...", + "companyName": "Company name", + "configure": "Configure", + "cores": "Cores", + "country": "COUNTRY", + "cpu": "CPU", + "cpuFrequency": "CPU Frequency", + "cpuLogical": "CPU (Logical)", + "cpuPhysical": "CPU (Physical)", + "cpuTemperature": "CPU Temperature", + "cpuUsage": "CPU usage", + "createA": "Create a", + "createMaintenance": "Create maintenance", + "createMaintenanceWindow": "Create maintenance window", + "createMonitor": "Create monitor", + "createNew": "Create new", + "createNotifications": { + "discordSettings": { + "description": "Configure your Discord webhook here", + "title": "Discord", + "webhookLabel": "Discord Webhook URL", + "webhookPlaceholder": "https://your-server.com/webhook" + }, + "emailSettings": { + "description": "Destination email addresses.", + "emailLabel": "Email address", + "emailPlaceholder": "e.g. john@example.com", + "title": "Email" + }, + "nameSettings": { + "description": "A descriptive name for your integration.", + "nameLabel": "Name", + "namePlaceholder": "e.g. Slack notifications", + "title": "Name" + }, + "pagerdutySettings": { + "description": "Configure your PagerDuty integration here", + "integrationKeyLabel": "Integration key", + "integrationKeyPlaceholder": "1234567890", + "title": "PagerDuty" + }, + "slackSettings": { + "description": "Configure your Slack webhook here", + "title": "Slack", + "webhookLabel": "Slack webhook URL", + "webhookPlaceholder": "https://hooks.slack.com/services/..." + }, + "title": "Create notification channel", + "typeSettings": { + "description": "Select the type of notification channel you want to create.", + "title": "Type", + "typeLabel": "Type" + }, + "webhookSettings": { + "description": "Configure your webhook here", + "title": "Webhook", + "webhookLabel": "Webhook URL", + "webhookPlaceholder": "https://your-server.com/webhook" + } + }, + "createYour": "Create your", + "date&Time": "Date & Time", + "delete": "Delete", + "deleteDialogDescription": "Once deleted, this monitor cannot be retrieved.", + "deleteDialogTitle": "Do you really want to delete this monitor?", + "deleteStatusPage": "Do you want to delete this status page?", + "deleteStatusPageConfirm": "Yes, delete status page", + "deleteStatusPageDescription": "Once deleted, your status page cannot be retrieved.", + "disk": "Disk", + "diskUsage": "Disk Usage", + "displayName": "Display name", + "distributedRightCategoryTitle": "Monitor", + "distributedStatusHeaderText": "Real-time, real-device coverage", + "distributedStatusServerMonitors": "Server Monitors", + "distributedStatusServerMonitorsDescription": "Monitor status of related servers", + "distributedStatusSubHeaderText": "Powered by millions devices worldwide, view a system performance by global region, country or city", + "distributedUptimeCreateAdvancedSettings": "Advanced settings", + "distributedUptimeCreateChecks": "Checks to perform", + "distributedUptimeCreateChecksDescription": "You can always add or remove checks after adding your site.", + "distributedUptimeCreateIncidentDescription": "When there is an incident, notify users.", + "distributedUptimeCreateIncidentNotification": "Incident notifications", + "distributedUptimeCreateSelectURL": "Here you can select the URL of the host, together with the type of monitor.", + "distributedUptimeDetailsNoMonitorHistory": "There is no check history for this monitor yet.", + "distributedUptimeDetailsStatusHeaderLastUpdate": "Last updated", + "distributedUptimeDetailsStatusHeaderUptime": "Uptime:", + "distributedUptimeStatus30Days": "30 days", + "distributedUptimeStatus60Days": "60 days", + "distributedUptimeStatus90Days": "90 days", + "distributedUptimeStatusBasicInfoDescription": "Define company name and the subdomain that your status page points to.", + "distributedUptimeStatusBasicInfoHeader": "Basic Information", + "distributedUptimeStatusCompanyNameLabel": "Company name", + "distributedUptimeStatusContactAdmin": "Please contact your administrator", + "distributedUptimeStatusCreateStatusPage": "status page", + "distributedUptimeStatusCreateStatusPageAccess": "Access", + "distributedUptimeStatusCreateStatusPageReady": "If your status page is ready, you can mark it as published.", + "distributedUptimeStatusCreateYour": "Create your", + "distributedUptimeStatusDevices": "Devices", + "distributedUptimeStatusEditYour": "Edit your", + "distributedUptimeStatusLogoDescription": "Upload a logo for your status page", + "distributedUptimeStatusLogoHeader": "Logo", + "distributedUptimeStatusLogoUploadButton": "Upload logo", + "distributedUptimeStatusPageAddressLabel": "Your status page address", + "distributedUptimeStatusPageDeleteConfirm": "Yes, delete status page", + "distributedUptimeStatusPageDeleteDescription": "Once deleted, your status page cannot be retrieved.", + "distributedUptimeStatusPageDeleteDialog": "Do you want to delete this status page?", + "distributedUptimeStatusPageNotPublic": "This status page is not public.", + "distributedUptimeStatusPageNotSetUp": "A status page is not set up.", + "distributedUptimeStatusPublishedLabel": "Published and visible to the public", + "distributedUptimeStatusStandardMonitorsDescription": "Attach standard monitors to your status page.", + "distributedUptimeStatusStandardMonitorsHeader": "Standard Monitors", + "distributedUptimeStatusUpt": "UPT", + "distributedUptimeStatusUptBurned": "UPT Burned", + "distributedUptimeStatusUptLogo": "Upt Logo", + "dockerContainerMonitoring": "Docker container monitoring", + "dockerContainerMonitoringDescription": "Check whether your Docker container is running or not.", + "duration": "Duration", + "edit": "Edit", + "editMaintenance": "Edit maintenance", + "editing": "Editing...", + "emailSent": "Email sent successfully", + "errorInvalidFieldId": "Invalid field ID provided", + "errorInvalidTypeId": "Invalid notification type provided", "errorPages": { "serverUnreachable": { - "toasts": { - "reconnected": "Successfully reconnected to the server.", - "stillUnreachable": "Server is still unreachable. Please try again later." - }, "alertBox": "Server Connection Error", "description": "We're unable to connect to the server. Please check your internet connection or verify your deployment configuration if the problem persists.", "retryButton": { "default": "Retry connection", "processing": "Connecting..." + }, + "toasts": { + "reconnected": "Successfully reconnected to the server.", + "stillUnreachable": "Server is still unreachable. Please try again later." } } }, - "createNotifications": { - "title": "Create notification channel", - "nameSettings": { - "title": "Name", - "description": "A descriptive name for your integration.", - "nameLabel": "Name", - "namePlaceholder": "e.g. Slack notifications" - }, - "typeSettings": { - "title": "Type", - "description": "Select the type of notification channel you want to create.", - "typeLabel": "Type" - }, - "emailSettings": { - "title": "Email", - "description": "Destination email addresses.", - "emailLabel": "Email address", - "emailPlaceholder": "e.g. john@example.com" - }, - "slackSettings": { - "title": "Slack", - "description": "Configure your Slack webhook here", - "webhookLabel": "Slack webhook URL", - "webhookPlaceholder": "https://hooks.slack.com/services/..." - }, - "pagerdutySettings": { - "title": "PagerDuty", - "description": "Configure your PagerDuty integration here", - "integrationKeyLabel": "Integration key", - "integrationKeyPlaceholder": "1234567890" - }, - "discordSettings": { - "title": "Discord", - "description": "Configure your Discord webhook here", - "webhookLabel": "Discord Webhook URL", - "webhookPlaceholder": "https://your-server.com/webhook" - }, - "webhookSettings": { - "title": "Webhook", - "description": "Configure your webhook here", - "webhookLabel": "Webhook URL", - "webhookPlaceholder": "https://your-server.com/webhook" - } + "expectedValue": "Expected value", + "export": { + "failed": "Failed to export monitors", + "success": "Monitors exported successfully!", + "title": "Export Monitors" }, - "notificationConfig": { - "title": "Notifications", - "description": "Select the notifications channels you want to use" + "failedToSendEmail": "Failed to send email", + "features": "Features", + "frequency": "Frequency", + "friendlyNameInput": "Friendly name", + "friendlyNamePlaceholder": "Maintenance at __ : __ for ___ minutes", + "gb": "GB", + "greeting": { + "append": "The afternoon is your playground—let's make it epic!", + "overview": "Here's an overview of your {{type}} monitors.", + "prepend": "Hey there" }, - "monitorStatus": { - "checkingEvery": "Checking every {{interval}}", - "withCaptureAgent": "with Capture agent {{version}}", - "up": "up", - "down": "down", - "paused": "paused" - }, - "advancedMatching": "Advanced matching", - "settingsEmailTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP", - "settingsEmailIgnoreTLS": "Ignore TLS - Disable STARTTLS", - "settingsEmailRequireTLS": "Require TLS - Force STARTTLS", - "settingsEmailRejectUnauthorized": "Reject Unauthorized", - "settingsEmailSecure": "Secure - Use SSL", - "settingsEmailPool": "Pool - Enable connection pooling", - "sendTestNotifications": "Send test notifications", - "selectAll": "Select all", + "high": "high", + "host": "Host", + "http": "HTTP", + "https": "HTTPS", + "ignoreTLSError": "Ignore TLS/SSL error", + "ignoreTLSErrorDescription": "Ignore TLS/SSL errors and continue checking the website's availability", + "incidentsOptionsHeader": "Incidents for:", + "incidentsOptionsHeaderFilterAll": "All", + "incidentsOptionsHeaderFilterBy": "Filter by:", + "incidentsOptionsHeaderFilterCannotResolve": "Cannot resolve", + "incidentsOptionsHeaderFilterDown": "Down", + "incidentsOptionsHeaderLastDay": "Last day", + "incidentsOptionsHeaderLastHour": "Last hour", + "incidentsOptionsHeaderLastWeek": "Last week", + "incidentsOptionsHeaderShow": "Show:", + "incidentsOptionsPlaceholderAllServers": "All servers", + "incidentsPageTitle": "Incidents", + "incidentsTableDateTime": "Date & Time", + "incidentsTableMessage": "Message", + "incidentsTableMonitorName": "Monitor Name", + "incidentsTableNoIncidents": "No incidents recorded", + "incidentsTablePaginationLabel": "incidents", + "incidentsTableStatus": "Status", + "incidentsTableStatusCode": "Status Code", + "infrastructureAlertNotificationDescription": "Send a notification to user(s) when thresholds exceed a specified percentage.", + "infrastructureAuthorizationSecretLabel": "Authorization secret", + "infrastructureCreateGeneralSettingsDescription": "Here you can select the URL of the host, together with the friendly name and authorization secret to connect to the server agent.", + "infrastructureCreateMonitor": "Create Infrastructure Monitor", + "infrastructureCreateYour": "Create your", + "infrastructureCustomizeAlerts": "Customize alerts", + "infrastructureDisplayNameLabel": "Display name", + "infrastructureEditMonitor": "Save Infrastructure Monitor", + "infrastructureEditYour": "Edit your", + "infrastructureMonitorCreated": "Infrastructure monitor created successfully!", + "infrastructureMonitorUpdated": "Infrastructure monitor updated successfully!", + "infrastructureProtocol": "Protocol", + "infrastructureServerRequirement": "The server you are monitoring must be running the", + "infrastructureServerUrlLabel": "Server URL", + "integrations": "Integrations", + "integrationsDiscord": "Discord", + "integrationsDiscordInfo": "Connect with Discord and view incidents directly in a channel", + "integrationsPrism": "Connect Prism to your favorite service.", + "integrationsSlack": "Slack", + "integrationsSlackInfo": "Connect with Slack and see incidents in a channel", + "integrationsZapier": "Zapier", + "integrationsZapierInfo": "Send all incidents to Zapier, and then see them everywhere", + "invalidFileFormat": "Unsupported file format!", + "invalidFileSize": "File size is too large!", + "inviteNoTokenFound": "No invite token found", + "loginHere": "Login here", "logsPage": { - "title": "Logs", "description": "This page shows the latest 1000 lines of logs from the Checkmate server", - "tabs": { - "queue": "Job queue", - "logs": "Server logs" - }, - "toast": { - "fetchLogsSuccess": "Logs fetched successfully" - }, "logLevelSelect": { "title": "Log level", "values": { "all": "All", - "info": "Info", - "warn": "Warn", + "debug": "Debug", "error": "Error", - "debug": "Debug" + "info": "Info", + "warn": "Warn" } + }, + "tabs": { + "logs": "Server logs", + "queue": "Job queue" + }, + "title": "Logs", + "toast": { + "fetchLogsSuccess": "Logs fetched successfully" } }, + "low": "low", + "maintenance": "maintenance", + "maintenanceRepeat": "Maintenance Repeat", + "maintenanceTableActionMenuDialogTitle": "Do you really want to remove this maintenance window?", + "maintenanceWindowDescription": "Your pings won't be sent during this time frame", + "maintenanceWindowName": "Maintenance Window Name", + "maskedPageSpeedKeyPlaceholder": "*************************************", + "matchMethod": "Match Method", + "mb": "MB", + "mem": "Mem", + "memory": "Memory", + "memoryUsage": "Memory usage", + "menu": { + "changelog": "Changelog", + "discussions": "Discussions", + "docs": "Docs", + "incidents": "Incidents", + "infrastructure": "Infrastructure", + "integrations": "Integrations", + "logOut": "Log out", + "logs": "Logs", + "maintenance": "Maintenance", + "notifications": "Notifications", + "pagespeed": "Pagespeed", + "password": "Password", + "profile": "Profile", + "settings": "Settings", + "statusPages": "Status pages", + "support": "Support", + "team": "Team", + "uptime": "Uptime" + }, + "message": "Message", + "monitor": "monitor", + "monitorActions": { + "export": "Export Monitors", + "import": "Import Monitors", + "title": "Export/Import" + }, + "monitorDisplayName": "Monitor display name", + "monitorState": { + "active": "Active", + "paused": "Paused", + "resumed": "Resumed" + }, + "monitorStatus": { + "checkingEvery": "Checking every {{interval}}", + "down": "down", + "paused": "paused", + "up": "up", + "withCaptureAgent": "with Capture agent {{version}}" + }, + "monitorStatusDown": "Monitor {name} ({url}) is DOWN and not responding", + "monitorStatusUp": "Monitor {name} ({url}) is now UP and responding", + "monitors": "monitors", + "monitorsToApply": "Monitors to apply maintenance window to", + "ms": "ms", + "navControls": "Controls", + "nextWindow": "Next window", + "notFoundButton": "Go to the main dashboard", + "notificationConfig": { + "description": "Select the notifications channels you want to use", + "title": "Notifications" + }, + "notifications": { + "addOrEditNotifications": "Add or edit notifications", + "create": { + "failed": "Failed to create notification", + "success": "Notification created successfully" + }, + "createButton": "Create notification channel", + "createTitle": "Notification channel", + "delete": { + "failed": "Failed to delete notification", + "success": "Notification deleted successfully" + }, + "discord": { + "description": "To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature.", + "label": "Discord", + "webhookLabel": "Discord Webhook URL", + "webhookPlaceholder": "https://discord.com/api/webhooks/...", + "webhookRequired": "Discord webhook URL is required" + }, + "edit": { + "failed": "Failed to update notification", + "success": "Notification updated successfully" + }, + "enableNotifications": "Enable {{platform}} notifications", + "fallback": { + "checks": [ + "Alert teams about downtime or performance issues", + "Let engineers know when incidents happen", + "Keep administrators informed of system changes" + ], + "title": "notification channel" + }, + "fetch": { + "failed": "Failed to fetch notifications", + "success": "Notifications fetched successfully" + }, + "integrationButton": "Notification Integration", + "networkError": "Network error occurred", + "slack": { + "description": "To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.", + "label": "Slack", + "webhookLabel": "Webhook URL", + "webhookPlaceholder": "https://hooks.slack.com/services/...", + "webhookRequired": "Slack webhook URL is required" + }, + "telegram": { + "chatIdLabel": "Your Chat ID", + "chatIdPlaceholder": "-1001234567890", + "description": "To enable Telegram notifications, create a Telegram bot using BotFather, an official bot for creating and managing Telegram bots. Then, get the API token and chat ID and write them down here.", + "fieldsRequired": "Telegram token and chat ID are required", + "label": "Telegram", + "tokenLabel": "Your bot token", + "tokenPlaceholder": "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11" + }, + "test": { + "failed": "Failed to send test notification", + "success": "Test notification sent successfully" + }, + "testFailed": "Failed to send test notification", + "testNotification": "Test notification", + "testNotificationDevelop": "Test notification 2", + "testSuccess": "Test notification sent successfully!", + "unsupportedType": "Unsupported notification type", + "webhook": { + "description": "You can set up a custom webhook to receive notifications when incidents occur.", + "label": "Webhooks", + "urlLabel": "Webhook URL", + "urlPlaceholder": "https://your-server.com/webhook", + "urlRequired": "Webhook URL is required" + } + }, + "notifyEmails": "Also notify via email to multiple addresses (coming soon)", + "notifySMS": "Notify via SMS (coming soon)", + "now": "Now", + "os": "OS", + "pageSpeedAddApiKey": "to add your API key.", + "pageSpeedConfigureSettingsDescription": "Here you can select the URL of the host, together with the type of monitor.", + "pageSpeedDetailsPerformanceReport": "Values are estimated and may vary.", + "pageSpeedDetailsPerformanceReportCalculator": "See calculator", + "pageSpeedLearnMoreLink": "Click here", + "pageSpeedMonitor": "PageSpeed monitor", + "pageSpeedWarning": "Warning: You haven't added a Google PageSpeed API key yet. Without it, the PageSpeed monitor won't function.", + "passwordPanel": { + "confirmNewPassword": "Confirm new password", + "currentPassword": "Current password", + "enterCurrentPassword": "Enter your current password", + "enterNewPassword": "Enter your new password", + "newPassword": "New password", + "passwordChangedSuccess": "Your password was changed successfully.", + "passwordInputIncorrect": "Your password input was incorrect.", + "passwordRequirements": "New password must contain at least 8 characters and must have at least one uppercase letter, one lowercase letter, one number and one special character.", + "saving": "Saving..." + }, + "pause": "Pause", + "pingMonitoring": "Ping monitoring", + "pingMonitoringDescription": "Check whether your server is available or not.", + "portMonitoring": "Port monitoring", + "portMonitoringDescription": "Check whether your port is open or not.", + "portToMonitor": "Port to monitor", + "publicLink": "Public link", + "publicURL": "Public URL", "queuePage": { - "title": "Queue", - "refreshButton": "Refresh", - "flushButton": "Flush queue", - "jobTable": { - "title": "Jobs currently in queue", - "idHeader": "Monitor ID", - "urlHeader": "URL", - "typeHeader": "Type", - "activeHeader": "Active", - "lockedAtHeader": "Locked at", - "runCountHeader": "Run count", - "failCountHeader": "Fail count", - "lastRunHeader": "Last run at", - "lastFinishedAtHeader": "Last finished at", - "lastRunTookHeader": "Last run took" - }, - "metricsTable": { - "title": "Queue metrics", - "metricHeader": "Metric", - "valueHeader": "Value" - }, "failedJobTable": { - "title": "Failed jobs", + "failCountHeader": "Fail count", + "failReasonHeader": "Fail reason", + "failedAtHeader": "Last failed at", "monitorIdHeader": "Monitor ID", "monitorUrlHeader": "Monitor URL", + "title": "Failed jobs" + }, + "flushButton": "Flush queue", + "jobTable": { + "activeHeader": "Active", "failCountHeader": "Fail count", - "failedAtHeader": "Last failed at", - "failReasonHeader": "Fail reason" + "idHeader": "Monitor ID", + "lastFinishedAtHeader": "Last finished at", + "lastRunHeader": "Last run at", + "lastRunTookHeader": "Last run took", + "lockedAtHeader": "Locked at", + "runCountHeader": "Run count", + "title": "Jobs currently in queue", + "typeHeader": "Type", + "urlHeader": "URL" + }, + "metricsTable": { + "metricHeader": "Metric", + "title": "Queue metrics", + "valueHeader": "Value" + }, + "refreshButton": "Refresh", + "title": "Queue" + }, + "remove": "Remove", + "removeLogo": "Remove Logo", + "repeat": "Repeat", + "reset": "Reset", + "response": "RESPONSE", + "responseTime": "Response time", + "resume": "Resume", + "roles": { + "admin": "Admin", + "demoUser": "Demo user", + "superAdmin": "Super admin", + "teamMember": "Team member" + }, + "save": "Save", + "selectAll": "Select all", + "sendTestNotifications": "Send test notifications", + "seperateEmails": "You can separate multiple emails with a comma", + + "settingsDisabled": "Disabled", + "settingsEmailUser": "Email user - Username for authentication, overrides email address if specified", + "settingsFailedToAddDemoMonitors": "Failed to add demo monitors", + "settingsFailedToClearStats": "Failed to clear stats", + "settingsFailedToDeleteMonitors": "Failed to delete all monitors", + "settingsFailedToSave": "Failed to save settings", + "settingsMonitorsDeleted": "Successfully deleted all monitors", + "settingsPage": { + "saveButtonLabel": "Save", + "timezoneSettings": { + "description": "Select the timezone used to display dates and times throughout the application.", + "label": "Display timezone", + "title": "Display timezone" + }, + "title": "Settings", + "uiSettings": { + "description": "Switch between light and dark mode, or change user interface language.", + "labelLanguage": "Language", + "labelTheme": "Theme mode", + "title": "Appearance" + }, + "pageSpeedSettings": { + "description": "Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.", + "labelApiKey": "PageSpeed API key", + "labelAPiKeySet": "API key is set. Click Reset to change it.", + "title": "Google PageSpeed API key" + }, + "urlSettings": { + "description": "Display the IP address or URL of monitor on the public Status page. If it's disabled, only the monitor name will be shown to protect sensitive information.", + "label": "Display IP/URL on status page", + "title": "Monitor IP/URL on Status Page", + "selectEnabled": "Enabled", + "selectDisabled": "Disabled" + }, + "statsSettings": { + "description": "Define how long you want to retain historical data. You can also clear all existing data.", + "labelTTL": "The days you want to keep monitoring history.", + "title": "Monitor history", + "labelTTLOptional": "0 for infinite", + "clearAllStatsDescription": "Clear all stats. This is irreversible.", + "clearAllStatsButton": "Clear all stats", + "clearAllStatsDialogTitle": "Do you want to clear all stats?", + "clearAllStatsDialogDescription": "Once removed, the monitoring history and stats cannot be retrieved.", + "clearAllStatsDialogConfirm": "Yes, clear all stats" + }, + "demoMonitorsSettings": { + "title": "Demo monitors", + "description": "Add sample monitors for demonstration purposes.", + "buttonAddMonitors": "Add demo monitors" + }, + "systemResetSettings": { + "title": "System reset", + "description": "Remove all monitors from your system.", + "buttonRemoveAllMonitors": "Remove all monitors", + "dialogTitle": "Do you want to remove all monitors?", + "dialogDescription": "Once removed, the monitors cannot be retrieved.", + "dialogConfirm": "Yes, remove all monitors" + }, + "emailSettings": { + "title": "Email", + "description": "Configure the email settings for your system. This is used to send notifications and alerts.", + "labelHost": "Email host - Hostname or IP address to connect to", + "labelPort": "Email port - Port to connect to", + "labelUser": "Email user - Username for authentication, overrides email address if specified", + "placeholderUser": "Leave empty if not required", + "labelAddress": "Email address - Used for authentication", + "labelPassword": "Email password - Password for authentication", + "labelPasswordSet": "Password is set. Click Reset to change it.", + "labelTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP", + "labelConnectionHost": "Email connection host - Hostname to use in the HELO/EHLO greeting", + "labelSecure": "Use SSL (recommended): Encrypt the connection using SSL/TLS", + "labelPool": "Enable connection pooling: Reuse existing connections to improve performance", + "labelIgnoreTLS": "Disable STARTTLS: Don't use TLS even if the server supports it", + "labelRequireTLS": "Force STARTTLS: Require TLS upgrade, fail if not supported", + "labelRejectUnauthorized": "Reject invalid certificates: Reject connections with self-signed or untrusted certificates", + "descriptionTransport": "This builds an SMTP transport for NodeMailer", + "linkTransport": "See specifications here", + "buttonSendTestEmail": "Send test e-mail" + }, + "aboutSettings": { + "title": "About", + "labelVersion": "Version", + "labelDevelopedBy": "Developed by Bluewave Labs" } }, - "export": { - "title": "Export Monitors", - "success": "Monitors exported successfully!", - "failed": "Failed to export monitors" + "settingsStatsCleared": "Stats cleared successfully", + "settingsSuccessSaved": "Settings saved successfully", + "settingsTestEmailFailed": "Failed to send test email", + "settingsTestEmailFailedWithReason": "Failed to send test email: {{reason}}", + "settingsTestEmailSuccess": "Test email sent successfully", + "settingsTestEmailUnknownError": "Unknown error", + "showAdminLoginLink": "Show \"Administrator? Login Here\" link on the status page", + "showCharts": "Show charts", + "showUptimePercentage": "Show uptime percentage", + "shown": "Shown", + "starPromptDescription": "See the latest releases and help grow the community on GitHub", + "starPromptTitle": "Star Checkmate", + "startTime": "Start time", + "state": "State", + "status": "Status", + "statusBreadCrumbsDetails": "Details", + "statusBreadCrumbsStatusPages": "Status Pages", + "statusCode": "Status code", + "statusMsg": { + "down": "Your site is down.", + "paused": "Monitoring is paused.", + "pending": "Pending...", + "up": "Your site is up." }, - "monitorActions": { - "title": "Export/Import", - "import": "Import Monitors", - "export": "Export Monitors" - } + "statusPageCreateAppearanceDescription": "Define the default look and feel of your public status page.", + "statusPageCreateBasicInfoDescription": "Define company name and the subdomain that your status page points to.", + "statusPageCreateBasicInfoStatusPageAddress": "Your status page address", + "statusPageCreateSelectTimeZoneDescription": "Select the timezone that your status page will be displayed in.", + "statusPageCreateSettings": "If your status page is ready, you can mark it as published.", + "statusPageCreateSettingsCheckboxLabel": "Published and visible to the public", + "statusPageCreateTabsContent": "Status page servers", + "statusPageCreateTabsContentDescription": "You can add any number of servers that you monitor to your status page. You can also reorder them for the best viewing experience.", + "statusPageCreateTabsContentFeaturesDescription": "Show more details on the status page", + "statusPageName": "Status page name", + "statusPageStatus": "A public status page is not set up.", + "statusPageStatusContactAdmin": "Please contact to your administrator", + "statusPageStatusNoPage": "There's no status page here.", + "statusPageStatusNotPublic": "This status page is not public.", + "statusPageStatusServiceStatus": "Service status", + "submit": "Submit", + "teamPanel": { + "cancel": "Cancel", + "email": "Email", + "emailToken": "E-mail token", + "filter": { + "all": "All", + "member": "Member" + }, + "getToken": "Get token", + "inviteDescription": "When you add a new team member, they will get access to all monitors.", + "inviteLink": "Invite link", + "inviteNewTeamMember": "Invite new team member", + "inviteTeamMember": "Invite a team member", + "noMembers": "There are no team members with this role", + "selectRole": "Select role", + "table": { + "created": "Created", + "email": "Email", + "name": "Name", + "role": "Role" + }, + "teamMembers": "Team members" + }, + "testLocale": "testLocale", + "timeZoneInfo": "All dates and times are in GMT+0 time zone.", + "timezone": "Timezone", + "title": "Title", + "tlsErrorIgnored": "TLS/SSL errors ignored", + "total": "Total", + "type": "Type", + "update": "Update", + "uptime": "Uptime", + "uptimeCreate": "The expected value is used to match against response result, and the match determines the status.", + "uptimeCreateJsonPath": "This expression will be evaluated against the reponse JSON data and the result will be used to match against the expected value. See", + "uptimeCreateJsonPathQuery": "for query language documentation.", + "uptimeGeneralInstructions": { + "docker": "Enter the Docker ID of your container. Docker IDs must be the full 64 char Docker ID. You can run docker inspect to get the full container ID.", + "http": "Enter the URL or IP to monitor (e.g., https://example.com/ or 192.168.1.100) and add a clear display name that appears on the dashboard.", + "ping": "Enter the IP address or hostname to ping (e.g., 192.168.1.100 or example.com) and add a clear display name that appears on the dashboard.", + "port": "Enter the URL or IP of the server, the port number and a clear display name that appears on the dashboard." + }, + "url": "URL", + "urlMonitor": "URL to monitor", + "used": "Used", + "webhookSendError": "Error sending webhook notification to {platform}", + "webhookSendSuccess": "Webhook notification sent successfully", + "webhookUnsupportedPlatform": "Unsupported platform: {platform}", + "websiteMonitoring": "Website monitoring", + "websiteMonitoringDescription": "Use HTTP(s) to monitor your website or API endpoint.", + "whenNewIncident": "When there is a new incident,", + "window": "window" } From 0d01a08304a46f69435e0f73bf99a7c69fe78ba9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Jun 2025 14:32:28 +0800 Subject: [PATCH 09/32] sort --- client/src/locales/en.json | 117 ++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 72dda4c64..8324bd5d7 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -660,7 +660,6 @@ "selectAll": "Select all", "sendTestNotifications": "Send test notifications", "seperateEmails": "You can separate multiple emails with a comma", - "settingsDisabled": "Disabled", "settingsEmailUser": "Email user - Username for authentication, overrides email address if specified", "settingsFailedToAddDemoMonitors": "Failed to add demo monitors", @@ -669,7 +668,63 @@ "settingsFailedToSave": "Failed to save settings", "settingsMonitorsDeleted": "Successfully deleted all monitors", "settingsPage": { + "aboutSettings": { + "labelDevelopedBy": "Developed by Bluewave Labs", + "labelVersion": "Version", + "title": "About" + }, + "demoMonitorsSettings": { + "buttonAddMonitors": "Add demo monitors", + "description": "Add sample monitors for demonstration purposes.", + "title": "Demo monitors" + }, + "emailSettings": { + "buttonSendTestEmail": "Send test e-mail", + "description": "Configure the email settings for your system. This is used to send notifications and alerts.", + "descriptionTransport": "This builds an SMTP transport for NodeMailer", + "labelAddress": "Email address - Used for authentication", + "labelConnectionHost": "Email connection host - Hostname to use in the HELO/EHLO greeting", + "labelHost": "Email host - Hostname or IP address to connect to", + "labelIgnoreTLS": "Disable STARTTLS: Don't use TLS even if the server supports it", + "labelPassword": "Email password - Password for authentication", + "labelPasswordSet": "Password is set. Click Reset to change it.", + "labelPool": "Enable connection pooling: Reuse existing connections to improve performance", + "labelPort": "Email port - Port to connect to", + "labelRejectUnauthorized": "Reject invalid certificates: Reject connections with self-signed or untrusted certificates", + "labelRequireTLS": "Force STARTTLS: Require TLS upgrade, fail if not supported", + "labelSecure": "Use SSL (recommended): Encrypt the connection using SSL/TLS", + "labelTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP", + "labelUser": "Email user - Username for authentication, overrides email address if specified", + "linkTransport": "See specifications here", + "placeholderUser": "Leave empty if not required", + "title": "Email" + }, + "pageSpeedSettings": { + "description": "Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.", + "labelAPiKeySet": "API key is set. Click Reset to change it.", + "labelApiKey": "PageSpeed API key", + "title": "Google PageSpeed API key" + }, "saveButtonLabel": "Save", + "statsSettings": { + "clearAllStatsButton": "Clear all stats", + "clearAllStatsDescription": "Clear all stats. This is irreversible.", + "clearAllStatsDialogConfirm": "Yes, clear all stats", + "clearAllStatsDialogDescription": "Once removed, the monitoring history and stats cannot be retrieved.", + "clearAllStatsDialogTitle": "Do you want to clear all stats?", + "description": "Define how long you want to retain historical data. You can also clear all existing data.", + "labelTTL": "The days you want to keep monitoring history.", + "labelTTLOptional": "0 for infinite", + "title": "Monitor history" + }, + "systemResetSettings": { + "buttonRemoveAllMonitors": "Remove all monitors", + "description": "Remove all monitors from your system.", + "dialogConfirm": "Yes, remove all monitors", + "dialogDescription": "Once removed, the monitors cannot be retrieved.", + "dialogTitle": "Do you want to remove all monitors?", + "title": "System reset" + }, "timezoneSettings": { "description": "Select the timezone used to display dates and times throughout the application.", "label": "Display timezone", @@ -682,68 +737,12 @@ "labelTheme": "Theme mode", "title": "Appearance" }, - "pageSpeedSettings": { - "description": "Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.", - "labelApiKey": "PageSpeed API key", - "labelAPiKeySet": "API key is set. Click Reset to change it.", - "title": "Google PageSpeed API key" - }, "urlSettings": { "description": "Display the IP address or URL of monitor on the public Status page. If it's disabled, only the monitor name will be shown to protect sensitive information.", "label": "Display IP/URL on status page", - "title": "Monitor IP/URL on Status Page", + "selectDisabled": "Disabled", "selectEnabled": "Enabled", - "selectDisabled": "Disabled" - }, - "statsSettings": { - "description": "Define how long you want to retain historical data. You can also clear all existing data.", - "labelTTL": "The days you want to keep monitoring history.", - "title": "Monitor history", - "labelTTLOptional": "0 for infinite", - "clearAllStatsDescription": "Clear all stats. This is irreversible.", - "clearAllStatsButton": "Clear all stats", - "clearAllStatsDialogTitle": "Do you want to clear all stats?", - "clearAllStatsDialogDescription": "Once removed, the monitoring history and stats cannot be retrieved.", - "clearAllStatsDialogConfirm": "Yes, clear all stats" - }, - "demoMonitorsSettings": { - "title": "Demo monitors", - "description": "Add sample monitors for demonstration purposes.", - "buttonAddMonitors": "Add demo monitors" - }, - "systemResetSettings": { - "title": "System reset", - "description": "Remove all monitors from your system.", - "buttonRemoveAllMonitors": "Remove all monitors", - "dialogTitle": "Do you want to remove all monitors?", - "dialogDescription": "Once removed, the monitors cannot be retrieved.", - "dialogConfirm": "Yes, remove all monitors" - }, - "emailSettings": { - "title": "Email", - "description": "Configure the email settings for your system. This is used to send notifications and alerts.", - "labelHost": "Email host - Hostname or IP address to connect to", - "labelPort": "Email port - Port to connect to", - "labelUser": "Email user - Username for authentication, overrides email address if specified", - "placeholderUser": "Leave empty if not required", - "labelAddress": "Email address - Used for authentication", - "labelPassword": "Email password - Password for authentication", - "labelPasswordSet": "Password is set. Click Reset to change it.", - "labelTLSServername": "TLS Servername - Optional Hostname for TLS Validation when host is an IP", - "labelConnectionHost": "Email connection host - Hostname to use in the HELO/EHLO greeting", - "labelSecure": "Use SSL (recommended): Encrypt the connection using SSL/TLS", - "labelPool": "Enable connection pooling: Reuse existing connections to improve performance", - "labelIgnoreTLS": "Disable STARTTLS: Don't use TLS even if the server supports it", - "labelRequireTLS": "Force STARTTLS: Require TLS upgrade, fail if not supported", - "labelRejectUnauthorized": "Reject invalid certificates: Reject connections with self-signed or untrusted certificates", - "descriptionTransport": "This builds an SMTP transport for NodeMailer", - "linkTransport": "See specifications here", - "buttonSendTestEmail": "Send test e-mail" - }, - "aboutSettings": { - "title": "About", - "labelVersion": "Version", - "labelDevelopedBy": "Developed by Bluewave Labs" + "title": "Monitor IP/URL on Status Page" } }, "settingsStatsCleared": "Stats cleared successfully", From 563cc8d03dec2037c5ec1ad35712472275f053a9 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 24 Jun 2025 14:45:04 +0800 Subject: [PATCH 10/32] fix label --- client/src/Pages/Settings/SettingsPagespeed.jsx | 2 +- client/src/locales/en.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/Pages/Settings/SettingsPagespeed.jsx b/client/src/Pages/Settings/SettingsPagespeed.jsx index e9eff79b5..157c75dac 100644 --- a/client/src/Pages/Settings/SettingsPagespeed.jsx +++ b/client/src/Pages/Settings/SettingsPagespeed.jsx @@ -67,7 +67,7 @@ const SettingsPagespeed = ({ {isApiKeySet === true && apiKeyHasBeenReset === false && ( - {t("settingsPage.pageSpeedSettings.labelAPiKeySet")} + {t("settingsPage.pageSpeedSettings.labelApiKeySet")}