From 2b017490a33280f24b7808cb044055399f5d3f1f Mon Sep 17 00:00:00 2001 From: mohadeseh safari Date: Fri, 20 Jun 2025 18:56:39 -0400 Subject: [PATCH 01/34] Move status page delete button to configuration page header (#2150) --- .../Create/Components/Tabs/index.jsx | 21 +++++++-- client/src/Pages/StatusPage/Create/index.jsx | 47 +++++++++++++++++-- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx b/client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx index 936a22130..60d86e1c9 100644 --- a/client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx +++ b/client/src/Pages/StatusPage/Create/Components/Tabs/index.jsx @@ -1,6 +1,6 @@ // Components import { TabContext } from "@mui/lab"; -import { Tab, useTheme } from "@mui/material"; +import { Tab } from "@mui/material"; import Settings from "./Settings"; import Content from "./Content"; @@ -22,8 +22,12 @@ const Tabs = ({ tab, setTab, TAB_LIST, + handleDelete, + isDeleteOpen, + setIsDeleteOpen, + isDeleting, + isLoading, }) => { - const theme = useTheme(); return ( - {TAB_LIST.map((tabLabel, idx) => ( + {TAB_LIST.map((tabLabel) => ( ) : ( { //Local state const [tab, setTab] = useState(0); const [progress, setProgress] = useState({ value: 0, isLoading: false }); + const [isDeleteOpen, setIsDeleteOpen] = useState(false); const [form, setForm] = useState({ isPublished: false, companyName: "", @@ -51,13 +55,13 @@ const CreateStatusPage = () => { //Utils const theme = useTheme(); const [monitors, isLoading, networkError] = useMonitorsFetch(); - const [createStatusPage, createStatusIsLoading, createStatusPageNetworkError] = - useCreateStatusPage(isCreate); + const [createStatusPage] = useCreateStatusPage(isCreate); const navigate = useNavigate(); const { t } = useTranslation(); - const [statusPage, statusPageMonitors, statusPageIsLoading, statusPageNetworkError] = + const [statusPage, statusPageMonitors, statusPageIsLoading, , fetchStatusPage] = useStatusPageFetch(isCreate, url); + const [deleteStatusPage, isDeleting] = useStatusPageDelete(fetchStatusPage, url); // Handlers const handleFormChange = (e) => { @@ -122,6 +126,12 @@ const CreateStatusPage = () => { setProgress({ value: 0, isLoading: false }); }; + const handleDelete = () => { + deleteStatusPage(); + setIsDeleteOpen(false); + navigate("/status"); + }; + const handleSubmit = async () => { let toSubmit = { ...form, @@ -220,6 +230,37 @@ const CreateStatusPage = () => { // Load fields return ( + + {!isCreate && ( + + + setIsDeleteOpen(false)} + open={isDeleteOpen} + confirmationButtonLabel={t("deleteStatusPageConfirm")} + description={t("deleteStatusPageDescription")} + isLoading={isDeleting || statusPageIsLoading} + /> + + )} Date: Fri, 20 Jun 2025 18:59:50 -0400 Subject: [PATCH 02/34] Modify --- .../Components/ControlsHeader/index.jsx | 24 +--------------- client/src/Pages/StatusPage/Status/index.jsx | 28 +------------------ 2 files changed, 2 insertions(+), 50 deletions(-) diff --git a/client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx b/client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx index dcbf96399..41814062a 100644 --- a/client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx +++ b/client/src/Pages/StatusPage/Status/Components/ControlsHeader/index.jsx @@ -11,7 +11,7 @@ import { useLocation } from "react-router-dom"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; -const Controls = ({ isDeleteOpen, setIsDeleteOpen, isDeleting, url, type }) => { +const Controls = ({ url, type }) => { const theme = useTheme(); const { t } = useTranslation(); const location = useLocation(); @@ -27,16 +27,6 @@ const Controls = ({ isDeleteOpen, setIsDeleteOpen, isDeleting, url, type }) => { direction="row" gap={theme.spacing(2)} > - - - - {/* Bulk create of uptime monitors */} - {title === "uptime monitor" && ( + {vowelStart ? "An" : "A"} {title} is used to: + + {checks?.map((check, index) => ( + + ))} + + {/* TODO - display a different fallback if user is not an admin*/} + {isAdmin && ( + <> - )} - - {/* Warning box for PageSpeed monitor */} - {title === "pagespeed monitor" && showPageSpeedWarning && ( - - svg": { - color: theme.palette.warningSecondary.contrastText, - }, - }, - }} + {/* Bulk create of uptime monitors */} + {title === "uptime monitor" && ( + + )} + + {/* Warning box for PageSpeed monitor */} + {title === "pagespeed monitor" && showPageSpeedWarning && ( + + svg": { + color: theme.palette.warningSecondary.contrastText, + }, + }, + }} + > + {settingsData?.pagespeedKeySet === false && ( + + )} + - - )} - - )} - - + )} + + )} + + ); }; From 32edb64da47f93a77c5f949ac78c840341baeb91 Mon Sep 17 00:00:00 2001 From: karenvicent Date: Wed, 25 Jun 2025 20:39:34 -0400 Subject: [PATCH 10/34] fix: Hardcoded dimensions in layout constraints --- client/src/Components/Fallback/index.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/Components/Fallback/index.jsx b/client/src/Components/Fallback/index.jsx index 864c92441..43f6bec30 100644 --- a/client/src/Components/Fallback/index.jsx +++ b/client/src/Components/Fallback/index.jsx @@ -89,9 +89,9 @@ const Fallback = ({ borderStyle: "dashed", height: "60vh", width: "45%", - minWidth: "400px", - maxHeight: "700px", - maxWidth: "800px", + minWidth: theme.spacing(200), + maxHeight: theme.breakpoints.values.sm, + maxWidth: theme.breakpoints.values.md, }} > Date: Thu, 26 Jun 2025 09:18:49 -0400 Subject: [PATCH 11/34] fix: Hardcoded dimensions in layout constraints with format --- client/src/Components/Fallback/index.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/Components/Fallback/index.jsx b/client/src/Components/Fallback/index.jsx index 43f6bec30..27879c42b 100644 --- a/client/src/Components/Fallback/index.jsx +++ b/client/src/Components/Fallback/index.jsx @@ -89,9 +89,9 @@ const Fallback = ({ borderStyle: "dashed", height: "60vh", width: "45%", - minWidth: theme.spacing(200), - maxHeight: theme.breakpoints.values.sm, - maxWidth: theme.breakpoints.values.md, + minWidth: theme.spacing(200), + maxHeight: theme.breakpoints.values.sm, + maxWidth: theme.breakpoints.values.md, }} > Date: Thu, 26 Jun 2025 14:37:35 -0400 Subject: [PATCH 12/34] fix: replace breakpoints with theme.spacing for consistent layout sizing --- client/src/Components/Fallback/index.jsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/client/src/Components/Fallback/index.jsx b/client/src/Components/Fallback/index.jsx index 27879c42b..919f2fd9e 100644 --- a/client/src/Components/Fallback/index.jsx +++ b/client/src/Components/Fallback/index.jsx @@ -87,21 +87,17 @@ const Fallback = ({ sx={{ display: "flex", borderStyle: "dashed", - height: "60vh", - width: "45%", + height: { sm: "50vh", md: "60vh" }, + width: { md: "45%", lg: "40%" }, minWidth: theme.spacing(200), - maxHeight: theme.breakpoints.values.sm, - maxWidth: theme.breakpoints.values.md, + maxHeight: theme.spacing(350), + maxWidth: theme.spacing(450), }} > {mode === "light" ? ( From 866b29db684ed72f380da50de3ce7223d55dc8a9 Mon Sep 17 00:00:00 2001 From: karenvicent Date: Fri, 27 Jun 2025 10:16:37 -0400 Subject: [PATCH 13/34] FIx: center placeholde box in the content area --- client/src/Components/Fallback/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/Components/Fallback/index.jsx b/client/src/Components/Fallback/index.jsx index 919f2fd9e..004ab4300 100644 --- a/client/src/Components/Fallback/index.jsx +++ b/client/src/Components/Fallback/index.jsx @@ -71,7 +71,7 @@ const Fallback = ({ Date: Fri, 27 Jun 2025 10:29:28 -0400 Subject: [PATCH 14/34] Fix: center placeholder in content area and merge branch 'develop' into fix/placeholder-center-align --- .../PageSpeed/Details/Components/Charts/PieChart.jsx | 10 +++++++++- .../Details/Components/PerformanceReport/index.jsx | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/client/src/Pages/PageSpeed/Details/Components/Charts/PieChart.jsx b/client/src/Pages/PageSpeed/Details/Components/Charts/PieChart.jsx index c9204c38a..eec075684 100644 --- a/client/src/Pages/PageSpeed/Details/Components/Charts/PieChart.jsx +++ b/client/src/Pages/PageSpeed/Details/Components/Charts/PieChart.jsx @@ -221,7 +221,15 @@ const PieChart = ({ audits }) => { const colorMap = getColors(performance); return ( - setExpand(false)}> + setExpand(false)} + sx={{ + display: "flex", + justifyContent: "center", + alignItems: "center", + width: "100%", + }} + > {expand ? ( { {t("pageSpeedDetailsPerformanceReport")}{" "} Date: Sun, 29 Jun 2025 12:14:42 -0400 Subject: [PATCH 15/34] fix deletion props passed to Tabs component --- client/src/Pages/StatusPage/Create/index.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/Pages/StatusPage/Create/index.jsx b/client/src/Pages/StatusPage/Create/index.jsx index 94eaa4f81..40cbb7a9a 100644 --- a/client/src/Pages/StatusPage/Create/index.jsx +++ b/client/src/Pages/StatusPage/Create/index.jsx @@ -284,6 +284,11 @@ const CreateStatusPage = () => { t("statusPage.contents", "Contents"), ]} isCreate={isCreate} + handleDelete={handleDelete} + isDeleteOpen={isDeleteOpen} + setIsDeleteOpen={setIsDeleteOpen} + isDeleting={isDeleting} + isLoading={statusPageIsLoading} /> Date: Tue, 1 Jul 2025 15:23:00 +0800 Subject: [PATCH 16/34] resolve strings --- .../Components/TabPanels/Account/PasswordPanel.jsx | 2 +- client/src/Hooks/monitorHooks.js | 4 ++-- client/src/locales/en.json | 11 +++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/client/src/Components/TabPanels/Account/PasswordPanel.jsx b/client/src/Components/TabPanels/Account/PasswordPanel.jsx index 84d16e8b0..81ce93946 100644 --- a/client/src/Components/TabPanels/Account/PasswordPanel.jsx +++ b/client/src/Components/TabPanels/Account/PasswordPanel.jsx @@ -214,7 +214,7 @@ const PasswordPanel = () => { { try { setIsLoading(true); await networkService.addDemoMonitors(); - createToast({ body: t("settingsDemoMonitorsAdded") }); + createToast({ body: t("monitorHooks.successAddDemoMonitors") }); } catch (error) { - createToast({ body: t("settingsFailedToAddDemoMonitors") }); + createToast({ body: t("monitorHooks.failureAddDemoMonitors") }); } finally { setIsLoading(false); } diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 117188852..313c640f7 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -1,4 +1,6 @@ { + "settingsAppearance": "Appearance", + "confirmPassword": "Confirm password", "submit": "Submit", "title": "Title", "distributedStatusHeaderText": "Real-time, real-device coverage", @@ -8,7 +10,6 @@ "settingsFailedToSave": "Failed to save settings", "settingsStatsCleared": "Stats cleared successfully", "settingsFailedToClearStats": "Failed to clear stats", - "settingsFailedToAddDemoMonitors": "Failed to add demo monitors", "settingsMonitorsDeleted": "Successfully deleted all monitors", "settingsFailedToDeleteMonitors": "Failed to delete all monitors", "starPromptTitle": "Star Checkmate", @@ -335,7 +336,9 @@ "uploadSuccess": "Monitors created successfully!", "validationFailed": "Validation failed", "noFileSelected": "No file selected", - "fallbackPage": "Import a file to upload a list of servers in bulk" + "fallbackPage": "Import a file to upload a list of servers in bulk", + "invalidFileType": "Invalid file type", + "uploadFailed": "Upload failed" }, "DeleteAccountTitle": "Remove account", "DeleteAccountButton": "Remove account", @@ -839,5 +842,9 @@ }, "statusPageCreate": { "buttonSave": "Save" + }, + "monitorHooks": { + "successAddDemoMonitors": "Successfully added demo monitors", + "failureAddDemoMonitors": "Failed to add demo monitors" } } From 19c5f4c8c358fddd537bc36b8a30d193a73b3b77 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 1 Jul 2025 15:25:45 +0800 Subject: [PATCH 17/34] update strings --- client/src/Pages/Settings/SettingsEmail.jsx | 5 +---- client/src/locales/en.json | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/client/src/Pages/Settings/SettingsEmail.jsx b/client/src/Pages/Settings/SettingsEmail.jsx index 6c527eaec..5897ee36d 100644 --- a/client/src/Pages/Settings/SettingsEmail.jsx +++ b/client/src/Pages/Settings/SettingsEmail.jsx @@ -87,10 +87,7 @@ const SettingsEmail = ({ !emailConfig.systemEmailPassword ) { createToast({ - body: t( - "settingsEmailRequiredFields", - "Email address, host, port and password are required" - ), + body: t("settingsPage.emailSettings.toastEmailRequiredFieldsError"), variant: "error", }); return; diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 313c640f7..d38c398a4 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -1,5 +1,6 @@ { "settingsAppearance": "Appearance", + "settingsDisplayTimezone": "Display timezone", "confirmPassword": "Confirm password", "submit": "Submit", "title": "Title", @@ -61,7 +62,7 @@ "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" + "webhookRequired": "Discord webhook URL is f" }, "telegram": { "label": "Telegram", @@ -792,7 +793,8 @@ "labelUser": "Email user - Username for authentication, overrides email address if specified", "linkTransport": "See specifications here", "placeholderUser": "Leave empty if not required", - "title": "Email" + "title": "Email", + "toastEmailRequiredFieldsError": "Email address, host, port and password are required" }, "pageSpeedSettings": { "description": "Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.", From 32954238045741ee36b27453c428a4704ea8e54e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 1 Jul 2025 15:27:23 +0800 Subject: [PATCH 18/34] add settingsSave --- client/src/locales/en.json | 1398 ++++++++++++++++++------------------ 1 file changed, 700 insertions(+), 698 deletions(-) diff --git a/client/src/locales/en.json b/client/src/locales/en.json index d38c398a4..1bd72bf51 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -1,542 +1,29 @@ { - "settingsAppearance": "Appearance", - "settingsDisplayTimezone": "Display timezone", - "confirmPassword": "Confirm password", - "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", - "settingsDisabled": "Disabled", - "settingsSuccessSaved": "Settings saved successfully", - "settingsFailedToSave": "Failed to save settings", - "settingsStatsCleared": "Stats cleared successfully", - "settingsFailedToClearStats": "Failed to clear stats", - "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 f" - }, - "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", - "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", - "invalidFileType": "Invalid file type", - "uploadFailed": "Upload failed" - }, - "DeleteAccountTitle": "Remove account", - "DeleteAccountButton": "Remove account", - "publicLink": "Public link", - "maskedPageSpeedKeyPlaceholder": "*************************************", - "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", - "settings": "Settings", - "support": "Support", - "discussions": "Discussions", - "docs": "Docs", - "changelog": "Changelog", - "profile": "Profile", - "password": "Password", - "team": "Team", - "logOut": "Log out", - "notifications": "Notifications", - "logs": "Logs" - }, - "settingsEmailUser": "Email user - Username for authentication, overrides email address if specified", - "state": "State", - "statusBreadCrumbsStatusPages": "Status Pages", - "statusBreadCrumbsDetails": "Details", - "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..." - }, - "emailSent": "Email sent successfully", - "failedToSendEmail": "Failed to send email", - "settingsTestEmailSuccess": "Test email sent successfully", - "settingsTestEmailFailed": "Failed to send test email", - "settingsTestEmailFailedWithReason": "Failed to send test email: {{reason}}", - "settingsTestEmailUnknownError": "Unknown error", - "statusMsg": { - "paused": "Monitoring is paused.", - "up": "Your site is up.", - "down": "Your site is down.", - "pending": "Pending..." - }, - "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." }, @@ -546,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" @@ -588,181 +174,509 @@ "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", + "invalidFileType": "Invalid file type", + "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", + "uploadFailed": "Upload failed", + "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", + "confirmPassword": "Confirm password", + "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." } } }, + "expectedValue": "Expected value", + "export": { + "failed": "Failed to export monitors", + "success": "Monitors exported successfully!", + "title": "Export Monitors" + }, + "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" + }, + "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", "incidentsOptionsHeaderFilterResolved": "Resolved", - "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" - } - }, - "notificationConfig": { - "title": "Notifications", - "description": "Select the notifications channels you want to use" - }, - "monitorStatus": { - "checkingEvery": "Checking every {{interval}}", - "withCaptureAgent": "with Capture agent {{version}}", - "up": "up", - "down": "down", - "paused": "paused" - }, - "advancedMatching": "Advanced matching", - "sendTestNotifications": "Send test notifications", - "selectAll": "Select all", - "showAdminLoginLink": "Show \"Administrator? Login Here\" link on the status page", + "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", + "monitorHooks": { + "failureAddDemoMonitors": "Failed to add demo monitors", + "successAddDemoMonitors": "Successfully added demo monitors" + }, + "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 f" + }, + "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" }, - "export": { - "title": "Export Monitors", - "success": "Monitors exported successfully!", - "failed": "Failed to export monitors" - }, - "monitorActions": { - "title": "Export/Import", - "import": "Import Monitors", - "export": "Export Monitors" + "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", + "settingsAppearance": "Appearance", + "settingsDisabled": "Disabled", + "settingsDisplayTimezone": "Display timezone", + "settingsEmailUser": "Email user - Username for authentication, overrides email address if specified", + "settingsFailedToClearStats": "Failed to clear stats", + "settingsFailedToDeleteMonitors": "Failed to delete all monitors", + "settingsFailedToSave": "Failed to save settings", + "settingsGeneralSettings": "General settings", + "settingsMonitorsDeleted": "Successfully deleted all monitors", "settingsPage": { "aboutSettings": { "labelDevelopedBy": "Developed by Bluewave Labs", @@ -842,11 +756,99 @@ "title": "Monitor IP/URL on Status Page" } }, + "settingsSave": "Save", + "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." + }, "statusPageCreate": { "buttonSave": "Save" }, - "monitorHooks": { - "successAddDemoMonitors": "Successfully added demo monitors", - "failureAddDemoMonitors": "Failed to add demo 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 35a9c081b5909a51385802b34e79c4259a6bedd1 Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Tue, 1 Jul 2025 15:54:50 +0530 Subject: [PATCH 19/34] Feat: Status Boxes in Incidents Page --- .../Components/OptionsHeader/index.jsx | 4 +- .../Components/StatusBoxes/StatusBox.jsx | 116 ++++++++++++++++++ .../Components/StatusBoxes/index.jsx | 43 +++++++ .../Components/StatusBoxes/skeleton.jsx | 36 ++++++ client/src/Pages/Incidents/index.jsx | 4 + 5 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx create mode 100644 client/src/Pages/Incidents/Components/StatusBoxes/index.jsx create mode 100644 client/src/Pages/Incidents/Components/StatusBoxes/skeleton.jsx diff --git a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx index 457c6fd96..08a9bcf1c 100644 --- a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx +++ b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx @@ -87,13 +87,13 @@ const OptionsHeader = ({ > {t("incidentsOptionsHeaderFilterCannotResolve")} - {/* */} + diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx new file mode 100644 index 000000000..ef7457a9e --- /dev/null +++ b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx @@ -0,0 +1,116 @@ +import PropTypes from "prop-types"; +import { useTheme } from "@emotion/react"; +import { Box, Stack, Typography } from "@mui/material"; +import Background from "../../../../assets/Images/background-grid.svg?react"; +import MonitorHeartOutlinedIcon from "@mui/icons-material/MonitorHeartOutlined"; +import TaskAltOutlinedIcon from "@mui/icons-material/TaskAltOutlined"; +import CancelOutlinedIcon from "@mui/icons-material/CancelOutlined"; +import WarningAmberRoundedIcon from "@mui/icons-material/WarningAmberRounded"; + +const StatusBox = ({ title, value, status }) => { + const theme = useTheme(); + let sharedStyles = { + position: "absolute", + right: 8, + opacity: 0.5, + "& svg path": { stroke: theme.palette.primary.contrastTextTertiary }, + }; + + let color; + let icon; + if (status === "up") { + color = theme.palette.success.lowContrast; + icon = ( + + + + ); + } else if (status === "down") { + color = theme.palette.error.lowContrast; + icon = ( + + + + ); + } else if (status === "paused") { + color = theme.palette.warning.lowContrast; + icon = ( + + + + ); + } else { + color = theme.palette.accent.main; + icon = ( + + + + ); + } + + return ( + + + + + + + + {title} + + {icon} + + + {value} + + + # + + + + + ); +}; + +StatusBox.propTypes = { + title: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + status: PropTypes.string, +}; + +export default StatusBox; \ No newline at end of file diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx new file mode 100644 index 000000000..ae29f4a8f --- /dev/null +++ b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx @@ -0,0 +1,43 @@ +import PropTypes from "prop-types"; +import { Stack } from "@mui/material"; +import StatusBox from "./StatusBox"; +import { useTheme } from "@emotion/react"; +import SkeletonLayout from "./skeleton"; + +const StatusBoxes = ({ shouldRender }) => { + const theme = useTheme(); + if (!shouldRender) return ; + return ( + + + + + + + ); +}; + +StatusBoxes.propTypes = { + shouldRender: PropTypes.bool, +}; + +export default StatusBoxes; \ No newline at end of file diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/skeleton.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/skeleton.jsx new file mode 100644 index 000000000..b9aa016b7 --- /dev/null +++ b/client/src/Pages/Incidents/Components/StatusBoxes/skeleton.jsx @@ -0,0 +1,36 @@ +import { Skeleton, Stack } from "@mui/material"; +import { useTheme } from "@emotion/react"; + +const SkeletonLayout = () => { + const theme = useTheme(); + return ( + + + + + + + ); +}; + +export default SkeletonLayout; diff --git a/client/src/Pages/Incidents/index.jsx b/client/src/Pages/Incidents/index.jsx index 09d4f0e25..8d668cb01 100644 --- a/client/src/Pages/Incidents/index.jsx +++ b/client/src/Pages/Incidents/index.jsx @@ -4,6 +4,7 @@ import Breadcrumbs from "../../Components/Breadcrumbs"; import GenericFallback from "../../Components/GenericFallback"; import IncidentTable from "./Components/IncidentTable"; import OptionsHeader from "./Components/OptionsHeader"; +import StatusBoxes from "./Components/StatusBoxes"; //Utils import { useTheme } from "@emotion/react"; @@ -62,6 +63,9 @@ const Incidents = () => { return ( + Date: Tue, 1 Jul 2025 17:55:50 +0530 Subject: [PATCH 20/34] Feat: Summary for Incidents --- .../Components/StatusBoxes/index.jsx | 20 +++++--- client/src/Pages/Incidents/index.jsx | 2 +- server/db/mongo/modules/checkModule.js | 23 +++++++++ server/db/mongo/modules/checkModuleQueries.js | 48 +++++++++++++++++++ 4 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 server/db/mongo/modules/checkModuleQueries.js diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx index ae29f4a8f..d44e00b22 100644 --- a/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx +++ b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx @@ -4,9 +4,9 @@ import StatusBox from "./StatusBox"; import { useTheme } from "@emotion/react"; import SkeletonLayout from "./skeleton"; -const StatusBoxes = ({ shouldRender }) => { +const StatusBoxes = ({ isLoading, statusCounts }) => { const theme = useTheme(); - if (!shouldRender) return ; + if (isLoading) return ; return ( { > ); }; StatusBoxes.propTypes = { - shouldRender: PropTypes.bool, + isLoading: PropTypes.bool, + statusCounts: PropTypes.shape({ + total: PropTypes.number, + resolved: PropTypes.number, + cannotResolve: PropTypes.number, + down: PropTypes.number, + }), }; export default StatusBoxes; \ No newline at end of file diff --git a/client/src/Pages/Incidents/index.jsx b/client/src/Pages/Incidents/index.jsx index 8d668cb01..708b443a5 100644 --- a/client/src/Pages/Incidents/index.jsx +++ b/client/src/Pages/Incidents/index.jsx @@ -64,7 +64,7 @@ const Incidents = () => { { } }; +/** + * Get checks and summary by team ID + * @async + * @param {string} teamId + * @returns {Promise} + * @throws {Error} + */ +const getChecksAndSummaryByTeamId = async ({ teamId }) => { + try { + const matchStage = { + teamId: new ObjectId(teamId), + } + const checks = await Check.aggregate(buildChecksAndSummaryByTeamIdPipeline({ matchStage })); + return checks[0].summary; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "getChecksAndSummaryByTeamId"; + throw error; + } +}; + /** * Delete all checks for a monitor * @async @@ -387,6 +409,7 @@ export { getChecksByTeam, ackCheck, ackAllChecks, + getChecksAndSummaryByTeamId, deleteChecks, deleteChecksByTeamId, updateChecksTTL, diff --git a/server/db/mongo/modules/checkModuleQueries.js b/server/db/mongo/modules/checkModuleQueries.js new file mode 100644 index 000000000..097389a52 --- /dev/null +++ b/server/db/mongo/modules/checkModuleQueries.js @@ -0,0 +1,48 @@ +const buildChecksAndSummaryByTeamIdPipeline = ({ matchStage }) => { + return [ + { $match: matchStage }, + { + $facet: { + summary: [ + { + $group: { + _id: null, + totalChecks: { $sum: { $cond: [{ $eq: ["$status", false] }, 1, 0] } }, + resolvedChecks: { + $sum: { + $cond: [{ $eq: ["$ack", true] }, 1, 0], + }, + }, + downChecks: { + $sum: { + $cond: [ + { $and: [{ $eq: ["$ack", false] }, { $eq: ["$status", false] }] }, + 1, + 0, + ], + }, + }, + cannotResolveChecks: { + $sum: { + $cond: [{ $eq: ["$statusCode", 5000] }, 1, 0], + }, + }, + }, + }, + { + $project: { + _id: 0, + }, + }, + ], + }, + }, + { + $project: { + summary: { $arrayElemAt: ["$summary", 0] }, + }, + }, + ]; +}; + +export { buildChecksAndSummaryByTeamIdPipeline }; From 644de5f34a36ab43b442f5106179b0dca6984c85 Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Tue, 1 Jul 2025 18:10:35 +0530 Subject: [PATCH 21/34] Feat: Hooks for Summary --- client/src/Hooks/checkHooks.js | 28 ++++++++++++++- .../Components/StatusBoxes/StatusBox.jsx | 22 ++++++------ .../Components/StatusBoxes/index.jsx | 35 ++++++++----------- client/src/Pages/Incidents/index.jsx | 8 +++-- client/src/Utils/NetworkService.js | 12 +++++++ server/controllers/checkController.js | 13 +++++++ server/db/mongo/modules/checkModule.js | 10 +++--- server/routes/checkRoute.js | 1 + 8 files changed, 91 insertions(+), 38 deletions(-) diff --git a/client/src/Hooks/checkHooks.js b/client/src/Hooks/checkHooks.js index 98fb0cfd5..a7dae8b9a 100644 --- a/client/src/Hooks/checkHooks.js +++ b/client/src/Hooks/checkHooks.js @@ -122,4 +122,30 @@ const useFetchChecksByMonitor = ({ return [checks, checksCount, isLoading, networkError]; }; -export { useFetchChecksByMonitor, useFetchChecksTeam }; +const useFetchChecksSummaryByTeamId = () => { + const [summary, setSummary] = useState(undefined); + const [isLoading, setIsLoading] = useState(false); + const [networkError, setNetworkError] = useState(false); + + useEffect(() => { + const fetchSummary = async () => { + try { + setIsLoading(true); + + const res = await networkService.getChecksAndSummaryByTeamId(); + setSummary(res.data.data); + } catch (error) { + setNetworkError(true); + createToast({ body: error.message }); + } finally { + setIsLoading(false); + } + }; + + fetchSummary(); + }, []); + + return [summary, isLoading, networkError]; +}; + +export { useFetchChecksByMonitor, useFetchChecksTeam, useFetchChecksSummaryByTeamId }; diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx index ef7457a9e..ac3d1660e 100644 --- a/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx +++ b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx @@ -22,31 +22,31 @@ const StatusBox = ({ title, value, status }) => { color = theme.palette.success.lowContrast; icon = ( - + ); } else if (status === "down") { color = theme.palette.error.lowContrast; icon = ( - + ); } else if (status === "paused") { color = theme.palette.warning.lowContrast; icon = ( - + ); } else { - color = theme.palette.accent.main; - icon = ( - - - - ); - } + color = theme.palette.accent.main; + icon = ( + + + + ); + } return ( { +const StatusBoxes = ({ isLoading, summary }) => { const theme = useTheme(); if (isLoading) return ; return ( @@ -15,35 +15,30 @@ const StatusBoxes = ({ isLoading, statusCounts }) => { > + + - - ); }; StatusBoxes.propTypes = { isLoading: PropTypes.bool, - statusCounts: PropTypes.shape({ - total: PropTypes.number, - resolved: PropTypes.number, - cannotResolve: PropTypes.number, - down: PropTypes.number, - }), + summary: PropTypes.object, }; -export default StatusBoxes; \ No newline at end of file +export default StatusBoxes; diff --git a/client/src/Pages/Incidents/index.jsx b/client/src/Pages/Incidents/index.jsx index 708b443a5..11946ae63 100644 --- a/client/src/Pages/Incidents/index.jsx +++ b/client/src/Pages/Incidents/index.jsx @@ -9,6 +9,7 @@ import StatusBoxes from "./Components/StatusBoxes"; //Utils import { useTheme } from "@emotion/react"; import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks"; +import { useFetchChecksSummaryByTeamId } from "../../Hooks/checkHooks"; import { useState, useEffect } from "react"; import NetworkError from "../../Components/GenericFallback/NetworkError"; import { useTranslation } from "react-i18next"; @@ -32,6 +33,8 @@ const Incidents = () => { //Utils const theme = useTheme(); const [monitors, , isLoading, networkError] = useFetchMonitorsByTeamId({}); + const [summary, isLoadingSummary, networkErrorSummary] = + useFetchChecksSummaryByTeamId(); const { monitorId } = useParams(); useEffect(() => { @@ -52,7 +55,7 @@ const Incidents = () => { setMonitorLookup(monitorLookup); }, [monitors]); - if (networkError) { + if (networkError || networkErrorSummary) { return ( @@ -64,7 +67,8 @@ const Incidents = () => { } The response from the axios GET request. + */ + getChecksAndSummaryByTeamId = async () => { + return this.axiosInstance.get(`/checks/team/summary`); + }; + /** * ************************************ * Update the status of a check diff --git a/server/controllers/checkController.js b/server/controllers/checkController.js index 8f9d0fbb5..e50d5b7fc 100755 --- a/server/controllers/checkController.js +++ b/server/controllers/checkController.js @@ -111,6 +111,19 @@ class CheckController { } }; + getChecksSummaryByTeamId = async (req, res, next) => { + try { + const { teamId } = req.user; + const summary = await this.db.getChecksSummaryByTeamId({ teamId }); + return res.success({ + msg: this.stringService.checkGetSummary, + data: summary, + }); + } catch (error) { + next(handleError(error, SERVICE_NAME, "getChecksSummaryByTeamId")); + } + }; + ackCheck = async (req, res, next) => { try { await ackCheckBodyValidation.validateAsync(req.body); diff --git a/server/db/mongo/modules/checkModule.js b/server/db/mongo/modules/checkModule.js index 835f358fa..7c9682557 100755 --- a/server/db/mongo/modules/checkModule.js +++ b/server/db/mongo/modules/checkModule.js @@ -312,12 +312,14 @@ const ackAllChecks = async (monitorId, teamId, ack, path) => { * @returns {Promise} * @throws {Error} */ -const getChecksAndSummaryByTeamId = async ({ teamId }) => { +const getChecksSummaryByTeamId = async ({ teamId }) => { try { const matchStage = { teamId: new ObjectId(teamId), - } - const checks = await Check.aggregate(buildChecksAndSummaryByTeamIdPipeline({ matchStage })); + }; + const checks = await Check.aggregate( + buildChecksAndSummaryByTeamIdPipeline({ matchStage }) + ); return checks[0].summary; } catch (error) { error.service = SERVICE_NAME; @@ -409,7 +411,7 @@ export { getChecksByTeam, ackCheck, ackAllChecks, - getChecksAndSummaryByTeamId, + getChecksSummaryByTeamId, deleteChecks, deleteChecksByTeamId, updateChecksTTL, diff --git a/server/routes/checkRoute.js b/server/routes/checkRoute.js index 7f91dbe31..4ac1e3730 100755 --- a/server/routes/checkRoute.js +++ b/server/routes/checkRoute.js @@ -14,6 +14,7 @@ class CheckRoutes { initRoutes() { this.router.get("/team", this.checkController.getChecksByTeam); + this.router.get("/team/summary", this.checkController.getChecksSummaryByTeamId); this.router.delete( "/team", isAllowed(["admin", "superadmin"]), From 278964500b7e88f7d6ff5856a422a9349ac36016 Mon Sep 17 00:00:00 2001 From: Br0wnHammer Date: Tue, 1 Jul 2025 18:23:11 +0530 Subject: [PATCH 22/34] Minor Changes --- .../Incidents/Components/StatusBoxes/StatusBox.jsx | 2 +- .../Pages/Incidents/Components/StatusBoxes/index.jsx | 10 ++++++---- client/src/locales/en.json | 3 ++- server/db/mongo/modules/checkModule.js | 6 +++--- server/db/mongo/modules/checkModuleQueries.js | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx index ac3d1660e..bc32fa765 100644 --- a/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx +++ b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx @@ -108,7 +108,7 @@ const StatusBox = ({ title, value, status }) => { }; StatusBox.propTypes = { - title: PropTypes.string, + title: PropTypes.string.isRequired, value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, status: PropTypes.string, }; diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx index 9d4193743..6ba2f1820 100644 --- a/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx +++ b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx @@ -2,10 +2,12 @@ import PropTypes from "prop-types"; import { Stack } from "@mui/material"; import StatusBox from "./StatusBox"; import { useTheme } from "@emotion/react"; +import { useTranslation } from "react-i18next"; import SkeletonLayout from "./skeleton"; const StatusBoxes = ({ isLoading, summary }) => { const theme = useTheme(); + const { t } = useTranslation(); if (isLoading) return ; return ( { justifyContent="space-between" > diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 8d26f75fd..d39be206e 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -385,7 +385,8 @@ "incidentsOptionsHeader": "Incidents for:", "incidentsOptionsHeaderFilterAll": "All", "incidentsOptionsHeaderFilterBy": "Filter by:", - "incidentsOptionsHeaderFilterCannotResolve": "Cannot resolve", + "incidentsOptionsHeaderTotalIncidents": "Total Incidents", + "incidentsOptionsHeaderFilterCannotResolve": "Cannot Resolve", "incidentsOptionsHeaderFilterDown": "Down", "incidentsOptionsHeaderFilterResolved": "Resolved", "incidentsOptionsHeaderLastDay": "Last day", diff --git a/server/db/mongo/modules/checkModule.js b/server/db/mongo/modules/checkModule.js index 7c9682557..fb0cc539e 100755 --- a/server/db/mongo/modules/checkModule.js +++ b/server/db/mongo/modules/checkModule.js @@ -5,7 +5,7 @@ import PageSpeedCheck from "../../models/PageSpeedCheck.js"; import User from "../../models/User.js"; import logger from "../../../utils/logger.js"; import { ObjectId } from "mongodb"; -import { buildChecksAndSummaryByTeamIdPipeline } from "./checkModuleQueries.js"; +import { buildChecksSummaryByTeamIdPipeline } from "./checkModuleQueries.js"; const SERVICE_NAME = "checkModule"; const dateRangeLookup = { @@ -318,12 +318,12 @@ const getChecksSummaryByTeamId = async ({ teamId }) => { teamId: new ObjectId(teamId), }; const checks = await Check.aggregate( - buildChecksAndSummaryByTeamIdPipeline({ matchStage }) + buildChecksSummaryByTeamIdPipeline({ matchStage }) ); return checks[0].summary; } catch (error) { error.service = SERVICE_NAME; - error.method = "getChecksAndSummaryByTeamId"; + error.method = "getChecksSummaryByTeamId"; throw error; } }; diff --git a/server/db/mongo/modules/checkModuleQueries.js b/server/db/mongo/modules/checkModuleQueries.js index 097389a52..7795fb6dc 100644 --- a/server/db/mongo/modules/checkModuleQueries.js +++ b/server/db/mongo/modules/checkModuleQueries.js @@ -1,4 +1,4 @@ -const buildChecksAndSummaryByTeamIdPipeline = ({ matchStage }) => { +const buildChecksSummaryByTeamIdPipeline = ({ matchStage }) => { return [ { $match: matchStage }, { @@ -45,4 +45,4 @@ const buildChecksAndSummaryByTeamIdPipeline = ({ matchStage }) => { ]; }; -export { buildChecksAndSummaryByTeamIdPipeline }; +export { buildChecksSummaryByTeamIdPipeline }; From 3d130bd8a50ad74a88b405d79a712af871495588 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 1 Jul 2025 23:35:11 +0800 Subject: [PATCH 23/34] sort en.json alphabetically --- client/src/locales/en.json | 1382 ++++++++++++++++++------------------ 1 file changed, 691 insertions(+), 691 deletions(-) diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 117188852..1e7069d2c 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -1,538 +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", - "settingsDisabled": "Disabled", - "settingsSuccessSaved": "Settings saved successfully", - "settingsFailedToSave": "Failed to save settings", - "settingsStatsCleared": "Stats cleared successfully", - "settingsFailedToClearStats": "Failed to clear stats", - "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", - "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" - }, - "DeleteAccountTitle": "Remove account", - "DeleteAccountButton": "Remove account", - "publicLink": "Public link", - "maskedPageSpeedKeyPlaceholder": "*************************************", - "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", - "settings": "Settings", - "support": "Support", - "discussions": "Discussions", - "docs": "Docs", - "changelog": "Changelog", - "profile": "Profile", - "password": "Password", - "team": "Team", - "logOut": "Log out", - "notifications": "Notifications", - "logs": "Logs" - }, - "settingsEmailUser": "Email user - Username for authentication, overrides email address if specified", - "state": "State", - "statusBreadCrumbsStatusPages": "Status Pages", - "statusBreadCrumbsDetails": "Details", - "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..." - }, - "emailSent": "Email sent successfully", - "failedToSendEmail": "Failed to send email", - "settingsTestEmailSuccess": "Test email sent successfully", - "settingsTestEmailFailed": "Failed to send test email", - "settingsTestEmailFailedWithReason": "Failed to send test email: {{reason}}", - "settingsTestEmailUnknownError": "Unknown error", - "statusMsg": { - "paused": "Monitoring is paused.", - "up": "Your site is up.", - "down": "Your site is down.", - "pending": "Pending..." - }, - "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." }, @@ -542,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" @@ -584,181 +174,500 @@ "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." } } }, + "expectedValue": "Expected value", + "export": { + "failed": "Failed to export monitors", + "success": "Monitors exported successfully!", + "title": "Export Monitors" + }, + "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" + }, + "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", "incidentsOptionsHeaderFilterResolved": "Resolved", - "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" - } - }, - "notificationConfig": { - "title": "Notifications", - "description": "Select the notifications channels you want to use" - }, - "monitorStatus": { - "checkingEvery": "Checking every {{interval}}", - "withCaptureAgent": "with Capture agent {{version}}", - "up": "up", - "down": "down", - "paused": "paused" - }, - "advancedMatching": "Advanced matching", - "sendTestNotifications": "Send test notifications", - "selectAll": "Select all", - "showAdminLoginLink": "Show \"Administrator? Login Here\" link on the status page", + "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" }, - "export": { - "title": "Export Monitors", - "success": "Monitors exported successfully!", - "failed": "Failed to export monitors" - }, - "monitorActions": { - "title": "Export/Import", - "import": "Import Monitors", - "export": "Export Monitors" + "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": { "aboutSettings": { "labelDevelopedBy": "Developed by Bluewave Labs", @@ -837,7 +746,98 @@ "title": "Monitor IP/URL on Status Page" } }, + "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." + }, "statusPageCreate": { "buttonSave": "Save" - } + }, + "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 708234118ab7590baa5658fe5511befb5bc9e4bf Mon Sep 17 00:00:00 2001 From: Alexander Holliday Date: Tue, 1 Jul 2025 23:42:31 +0800 Subject: [PATCH 24/34] Revert "sort en.json alphabetically" --- client/src/locales/en.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 1e7069d2c..8d26f75fd 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -746,6 +746,7 @@ "title": "Monitor IP/URL on Status Page" } }, + "settingsSave": "Save", "settingsStatsCleared": "Stats cleared successfully", "settingsSuccessSaved": "Settings saved successfully", "settingsTestEmailFailed": "Failed to send test email", @@ -774,6 +775,7 @@ "buttonSave": "Save" }, "statusPageCreateAppearanceDescription": "Define the default look and feel of your public status page.", + "statusPageCreateAppearanceTitle": "Appearance", "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.", From 2e869310b88d6c472335fe5a6860837fcdf2e048 Mon Sep 17 00:00:00 2001 From: Amol Date: Tue, 1 Jul 2025 22:44:42 +0530 Subject: [PATCH 25/34] feat: disable send test notification when 0 notification configured --- .../MonitorDetailsControlHeader/index.jsx | 61 +++++++++++++++---- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/client/src/Components/MonitorDetailsControlHeader/index.jsx b/client/src/Components/MonitorDetailsControlHeader/index.jsx index 1d253e3d5..9a76af551 100644 --- a/client/src/Components/MonitorDetailsControlHeader/index.jsx +++ b/client/src/Components/MonitorDetailsControlHeader/index.jsx @@ -2,6 +2,7 @@ import Stack from "@mui/material/Stack"; import Status from "./status"; import Skeleton from "./skeleton"; import Button from "@mui/material/Button"; +import { Tooltip } from "@mui/material"; import SettingsOutlinedIcon from "@mui/icons-material/SettingsOutlined"; import PauseOutlinedIcon from "@mui/icons-material/PauseOutlined"; import PlayArrowOutlinedIcon from "@mui/icons-material/PlayArrowOutlined"; @@ -40,6 +41,8 @@ const MonitorDetailsControlHeader = ({ const { t } = useTranslation(); const [pauseMonitor, isPausing, error] = usePauseMonitor(); + const isTestNotificationsDisabled = monitor?.notifications?.length === 0; + // const [isSending, emailError, sendTestEmail] = useSendTestEmail(); const [testAllNotifications, isSending, errorAllNotifications] = @@ -60,20 +63,52 @@ const MonitorDetailsControlHeader = ({ direction="row" gap={theme.spacing(2)} > - + {isTestNotificationsDisabled ? ( + + + + ) : ( + + )} + - - ) : ( + - )} + - {/* */} + diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx new file mode 100644 index 000000000..b19f017e7 --- /dev/null +++ b/client/src/Pages/Incidents/Components/StatusBoxes/StatusBox.jsx @@ -0,0 +1,116 @@ +import PropTypes from "prop-types"; +import { useTheme } from "@emotion/react"; +import { Box, Stack, Typography } from "@mui/material"; +import Background from "../../../../assets/Images/background-grid.svg?react"; +import MonitorHeartOutlinedIcon from "@mui/icons-material/MonitorHeartOutlined"; +import TaskAltOutlinedIcon from "@mui/icons-material/TaskAltOutlined"; +import CancelOutlinedIcon from "@mui/icons-material/CancelOutlined"; +import WarningAmberRoundedIcon from "@mui/icons-material/WarningAmberRounded"; + +const StatusBox = ({ title, value, status }) => { + const theme = useTheme(); + let sharedStyles = { + position: "absolute", + right: 8, + opacity: 0.5, + "& svg path": { stroke: theme.palette.primary.contrastTextTertiary }, + }; + + let color; + let icon; + if (status === "up") { + color = theme.palette.success.lowContrast; + icon = ( + + + + ); + } else if (status === "down") { + color = theme.palette.error.lowContrast; + icon = ( + + + + ); + } else if (status === "paused") { + color = theme.palette.warning.lowContrast; + icon = ( + + + + ); + } else { + color = theme.palette.accent.main; + icon = ( + + + + ); + } + + return ( + + + + + + + + {title} + + {icon} + + + {value} + + + # + + + + + ); +}; + +StatusBox.propTypes = { + title: PropTypes.string.isRequired, + value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + status: PropTypes.string, +}; + +export default StatusBox; diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx new file mode 100644 index 000000000..6ba2f1820 --- /dev/null +++ b/client/src/Pages/Incidents/Components/StatusBoxes/index.jsx @@ -0,0 +1,46 @@ +import PropTypes from "prop-types"; +import { Stack } from "@mui/material"; +import StatusBox from "./StatusBox"; +import { useTheme } from "@emotion/react"; +import { useTranslation } from "react-i18next"; +import SkeletonLayout from "./skeleton"; + +const StatusBoxes = ({ isLoading, summary }) => { + const theme = useTheme(); + const { t } = useTranslation(); + if (isLoading) return ; + return ( + + + + + + + ); +}; + +StatusBoxes.propTypes = { + isLoading: PropTypes.bool, + summary: PropTypes.object, +}; + +export default StatusBoxes; diff --git a/client/src/Pages/Incidents/Components/StatusBoxes/skeleton.jsx b/client/src/Pages/Incidents/Components/StatusBoxes/skeleton.jsx new file mode 100644 index 000000000..b9aa016b7 --- /dev/null +++ b/client/src/Pages/Incidents/Components/StatusBoxes/skeleton.jsx @@ -0,0 +1,36 @@ +import { Skeleton, Stack } from "@mui/material"; +import { useTheme } from "@emotion/react"; + +const SkeletonLayout = () => { + const theme = useTheme(); + return ( + + + + + + + ); +}; + +export default SkeletonLayout; diff --git a/client/src/Pages/Incidents/index.jsx b/client/src/Pages/Incidents/index.jsx index 09d4f0e25..11946ae63 100644 --- a/client/src/Pages/Incidents/index.jsx +++ b/client/src/Pages/Incidents/index.jsx @@ -4,10 +4,12 @@ import Breadcrumbs from "../../Components/Breadcrumbs"; import GenericFallback from "../../Components/GenericFallback"; import IncidentTable from "./Components/IncidentTable"; import OptionsHeader from "./Components/OptionsHeader"; +import StatusBoxes from "./Components/StatusBoxes"; //Utils import { useTheme } from "@emotion/react"; import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks"; +import { useFetchChecksSummaryByTeamId } from "../../Hooks/checkHooks"; import { useState, useEffect } from "react"; import NetworkError from "../../Components/GenericFallback/NetworkError"; import { useTranslation } from "react-i18next"; @@ -31,6 +33,8 @@ const Incidents = () => { //Utils const theme = useTheme(); const [monitors, , isLoading, networkError] = useFetchMonitorsByTeamId({}); + const [summary, isLoadingSummary, networkErrorSummary] = + useFetchChecksSummaryByTeamId(); const { monitorId } = useParams(); useEffect(() => { @@ -51,7 +55,7 @@ const Incidents = () => { setMonitorLookup(monitorLookup); }, [monitors]); - if (networkError) { + if (networkError || networkErrorSummary) { return ( @@ -62,6 +66,10 @@ const Incidents = () => { return ( + { if (status === "up") { color = theme.palette.success.lowContrast; icon = ( - + ); } else if (status === "down") { color = theme.palette.error.lowContrast; icon = ( - + ); } else if (status === "paused") { color = theme.palette.warning.lowContrast; icon = ( - + ); @@ -75,15 +75,15 @@ const StatusBox = ({ title, value, status }) => { {value} } The response from the axios GET request. + */ + getChecksAndSummaryByTeamId = async () => { + return this.axiosInstance.get(`/checks/team/summary`); + }; + /** * ************************************ * Update the status of a check diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 8d26f75fd..9e6c9fe91 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -197,12 +197,14 @@ "basicInformation": "Basic Information", "bulkImport": { "fallbackPage": "Import a file to upload a list of servers in bulk", + "invalidFileType": "Invalid file type", "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", + "uploadFailed": "Upload failed", "uploadSuccess": "Monitors created successfully!", "validationFailed": "Validation failed" }, @@ -226,6 +228,7 @@ "commonSaving": "Saving...", "companyName": "Company name", "configure": "Configure", + "confirmPassword": "Confirm password", "cores": "Cores", "country": "COUNTRY", "cpu": "CPU", @@ -385,7 +388,8 @@ "incidentsOptionsHeader": "Incidents for:", "incidentsOptionsHeaderFilterAll": "All", "incidentsOptionsHeaderFilterBy": "Filter by:", - "incidentsOptionsHeaderFilterCannotResolve": "Cannot resolve", + "incidentsOptionsHeaderTotalIncidents": "Total Incidents", + "incidentsOptionsHeaderFilterCannotResolve": "Cannot Resolve", "incidentsOptionsHeaderFilterDown": "Down", "incidentsOptionsHeaderFilterResolved": "Resolved", "incidentsOptionsHeaderLastDay": "Last day", @@ -488,6 +492,11 @@ "title": "Export/Import" }, "monitorDisplayName": "Monitor display name", + "monitorHooks": { + "failureAddDemoMonitors": "Failed to add demo monitors", + "successAddDemoMonitors": "Successfully added demo monitors" + }, + "monitorState": { "active": "Active", "paused": "Paused", @@ -661,12 +670,14 @@ "selectAll": "Select all", "sendTestNotifications": "Send test notifications", "seperateEmails": "You can separate multiple emails with a comma", + "settingsAppearance": "Appearance", "settingsDisabled": "Disabled", + "settingsDisplayTimezone": "Display timezone", "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", + "settingsGeneralSettings": "General settings", "settingsMonitorsDeleted": "Successfully deleted all monitors", "settingsPage": { "aboutSettings": { @@ -698,7 +709,8 @@ "labelUser": "Email user - Username for authentication, overrides email address if specified", "linkTransport": "See specifications here", "placeholderUser": "Leave empty if not required", - "title": "Email" + "title": "Email", + "toastEmailRequiredFieldsError": "Email address, host, port and password are required" }, "pageSpeedSettings": { "description": "Enter your Google PageSpeed API key to enable Google PageSpeed monitoring. Click Reset to update the key.", diff --git a/server/controllers/checkController.js b/server/controllers/checkController.js index 8f9d0fbb5..e50d5b7fc 100755 --- a/server/controllers/checkController.js +++ b/server/controllers/checkController.js @@ -111,6 +111,19 @@ class CheckController { } }; + getChecksSummaryByTeamId = async (req, res, next) => { + try { + const { teamId } = req.user; + const summary = await this.db.getChecksSummaryByTeamId({ teamId }); + return res.success({ + msg: this.stringService.checkGetSummary, + data: summary, + }); + } catch (error) { + next(handleError(error, SERVICE_NAME, "getChecksSummaryByTeamId")); + } + }; + ackCheck = async (req, res, next) => { try { await ackCheckBodyValidation.validateAsync(req.body); diff --git a/server/db/mongo/modules/checkModule.js b/server/db/mongo/modules/checkModule.js index b7d9f4fb2..fb0cc539e 100755 --- a/server/db/mongo/modules/checkModule.js +++ b/server/db/mongo/modules/checkModule.js @@ -5,6 +5,7 @@ import PageSpeedCheck from "../../models/PageSpeedCheck.js"; import User from "../../models/User.js"; import logger from "../../../utils/logger.js"; import { ObjectId } from "mongodb"; +import { buildChecksSummaryByTeamIdPipeline } from "./checkModuleQueries.js"; const SERVICE_NAME = "checkModule"; const dateRangeLookup = { @@ -304,6 +305,29 @@ const ackAllChecks = async (monitorId, teamId, ack, path) => { } }; +/** + * Get checks and summary by team ID + * @async + * @param {string} teamId + * @returns {Promise} + * @throws {Error} + */ +const getChecksSummaryByTeamId = async ({ teamId }) => { + try { + const matchStage = { + teamId: new ObjectId(teamId), + }; + const checks = await Check.aggregate( + buildChecksSummaryByTeamIdPipeline({ matchStage }) + ); + return checks[0].summary; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "getChecksSummaryByTeamId"; + throw error; + } +}; + /** * Delete all checks for a monitor * @async @@ -387,6 +411,7 @@ export { getChecksByTeam, ackCheck, ackAllChecks, + getChecksSummaryByTeamId, deleteChecks, deleteChecksByTeamId, updateChecksTTL, diff --git a/server/db/mongo/modules/checkModuleQueries.js b/server/db/mongo/modules/checkModuleQueries.js new file mode 100644 index 000000000..7795fb6dc --- /dev/null +++ b/server/db/mongo/modules/checkModuleQueries.js @@ -0,0 +1,48 @@ +const buildChecksSummaryByTeamIdPipeline = ({ matchStage }) => { + return [ + { $match: matchStage }, + { + $facet: { + summary: [ + { + $group: { + _id: null, + totalChecks: { $sum: { $cond: [{ $eq: ["$status", false] }, 1, 0] } }, + resolvedChecks: { + $sum: { + $cond: [{ $eq: ["$ack", true] }, 1, 0], + }, + }, + downChecks: { + $sum: { + $cond: [ + { $and: [{ $eq: ["$ack", false] }, { $eq: ["$status", false] }] }, + 1, + 0, + ], + }, + }, + cannotResolveChecks: { + $sum: { + $cond: [{ $eq: ["$statusCode", 5000] }, 1, 0], + }, + }, + }, + }, + { + $project: { + _id: 0, + }, + }, + ], + }, + }, + { + $project: { + summary: { $arrayElemAt: ["$summary", 0] }, + }, + }, + ]; +}; + +export { buildChecksSummaryByTeamIdPipeline }; diff --git a/server/routes/checkRoute.js b/server/routes/checkRoute.js index 7f91dbe31..4ac1e3730 100755 --- a/server/routes/checkRoute.js +++ b/server/routes/checkRoute.js @@ -14,6 +14,7 @@ class CheckRoutes { initRoutes() { this.router.get("/team", this.checkController.getChecksByTeam); + this.router.get("/team/summary", this.checkController.getChecksSummaryByTeamId); this.router.delete( "/team", isAllowed(["admin", "superadmin"]), From e2e1eff289035b3c4a9597097929968e51ffcaab Mon Sep 17 00:00:00 2001 From: Amol Date: Thu, 3 Jul 2025 01:26:33 +0530 Subject: [PATCH 29/34] feat: add language localization and refactor to remove duplicate ternary op --- .../Components/MonitorDetailsControlHeader/index.jsx | 10 +++------- client/src/locales/ar.json | 1 + client/src/locales/cs.json | 1 + client/src/locales/de.json | 1 + client/src/locales/en.json | 1 + client/src/locales/es.json | 1 + client/src/locales/fi.json | 1 + client/src/locales/fr.json | 1 + client/src/locales/pt-BR.json | 1 + client/src/locales/ru.json | 1 + client/src/locales/tr.json | 1 + client/src/locales/zh-TW.json | 1 + 12 files changed, 14 insertions(+), 7 deletions(-) diff --git a/client/src/Components/MonitorDetailsControlHeader/index.jsx b/client/src/Components/MonitorDetailsControlHeader/index.jsx index 67bf10f22..4674a1fb7 100644 --- a/client/src/Components/MonitorDetailsControlHeader/index.jsx +++ b/client/src/Components/MonitorDetailsControlHeader/index.jsx @@ -43,6 +43,8 @@ const MonitorDetailsControlHeader = ({ const isTestNotificationsDisabled = monitor?.notifications?.length === 0; + const tooltipTitle = isTestNotificationsDisabled ? t("testNotificationsDisabled") : ""; + // const [isSending, emailError, sendTestEmail] = useSendTestEmail(); const [testAllNotifications, isSending, errorAllNotifications] = @@ -66,13 +68,7 @@ const MonitorDetailsControlHeader = ({ + ) : ( + + {t("incidentsTableResolvedAt")}{" "} + {formatDateWithTz(row.ackAt, "YYYY-MM-DD HH:mm:ss A", uiTimezone)} + + ); + }, + }, ]; - if (!shouldRender || isLoading) return ; + if (isLoading || resolveLoading) return ; if (networkError) { return ( @@ -149,10 +194,12 @@ const IncidentTable = ({ }; IncidentTable.propTypes = { - shouldRender: PropTypes.bool, + isLoading: PropTypes.bool, monitors: PropTypes.object, selectedMonitor: PropTypes.string, filter: PropTypes.string, dateRange: PropTypes.string, + updateTrigger: PropTypes.bool, + setUpdateTrigger: PropTypes.func, }; export default IncidentTable; diff --git a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx index 08a9bcf1c..259880223 100644 --- a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx +++ b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx @@ -21,6 +21,12 @@ const OptionsHeader = ({ const theme = useTheme(); const { t } = useTranslation(); const monitorNames = typeof monitors !== "undefined" ? Object.values(monitors) : []; + const filterOptions = [ + { _id: "all", name: t("incidentsOptionsHeaderFilterAll") }, + { _id: "down", name: t("incidentsOptionsHeaderFilterDown") }, + { _id: "resolve", name: t("incidentsOptionsHeaderFilterCannotResolve") }, + { _id: "resolved", name: t("incidentsOptionsHeaderFilterResolved") }, + ]; // The stacks below which are three in number have the same style so const stackStyles = { @@ -65,36 +71,16 @@ const OptionsHeader = ({ > {t("incidentsOptionsHeaderFilterBy")} - - - - - - +