From b44d1429202f0539c88bc262e0d641a508b9ad7a Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 1 Mar 2025 22:36:07 -0800 Subject: [PATCH 01/20] Implemented notification modal. --- src/Pages/Uptime/Create/index.jsx | 15 +- .../NotificationIntegrationModal.jsx | 413 ++++++++++++++++++ 2 files changed, 427 insertions(+), 1 deletion(-) create mode 100644 src/Pages/Uptime/Details/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx diff --git a/src/Pages/Uptime/Create/index.jsx b/src/Pages/Uptime/Create/index.jsx index edad33d20..b9bb7eb8f 100644 --- a/src/Pages/Uptime/Create/index.jsx +++ b/src/Pages/Uptime/Create/index.jsx @@ -23,6 +23,7 @@ import Radio from "../../../Components/Inputs/Radio"; import Checkbox from "../../../Components/Inputs/Checkbox"; import Select from "../../../Components/Inputs/Select"; import ConfigBox from "../../../Components/ConfigBox"; +import NotificationIntegrationModal from "../Details/Components/NotificationIntegrationModal/NotificationIntegrationModal"; const CreateMonitor = () => { const MS_PER_MINUTE = 60000; const SELECT_VALUES = [ @@ -80,6 +81,11 @@ const CreateMonitor = () => { ]; // State + const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false); + + const handleOpenNotificationModal = () => { + setIsNotificationModalOpen(true); + }; const [errors, setErrors] = useState({}); const [https, setHttps] = useState(true); const [monitor, setMonitor] = useState({ @@ -411,7 +417,7 @@ const CreateMonitor = () => { @@ -512,6 +518,13 @@ const CreateMonitor = () => { + + setIsNotificationModalOpen(false)} + monitor={monitor} + setMonitor={setMonitor} + /> ); }; diff --git a/src/Pages/Uptime/Details/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Pages/Uptime/Details/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx new file mode 100644 index 000000000..eca6a78d0 --- /dev/null +++ b/src/Pages/Uptime/Details/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -0,0 +1,413 @@ +import { useState } from "react"; +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Stack, + Typography, + Box, + Tabs, + Tab, + Divider +} from "@mui/material"; +import { useTheme } from "@emotion/react"; +import TextInput from "../../../../../../src/Components/Inputs/TextInput"; +import Checkbox from "../../../../../../src/Components/Inputs/Checkbox"; + +// Tab Panel component +function TabPanel({ children, value, index, ...other }) { + return ( + + ); +} + +const NotificationIntegrationModal = ({ + open, + onClose, + monitor, + setMonitor +}) => { + const theme = useTheme(); + const [tabValue, setTabValue] = useState(0); + const [integrations, setIntegrations] = useState({ + slack: monitor?.notifications?.some(n => n.type === "slack") || false, + slackWebhook: monitor?.notifications?.find(n => n.type === "slack")?.webhook || "", + discord: monitor?.notifications?.some(n => n.type === "discord") || false, + discordWebhook: monitor?.notifications?.find(n => n.type === "discord")?.webhook || "", + telegram: monitor?.notifications?.some(n => n.type === "telegram") || false, + telegramToken: monitor?.notifications?.find(n => n.type === "telegram")?.token || "", + telegramChatId: monitor?.notifications?.find(n => n.type === "telegram")?.chatId || "", + webhook: monitor?.notifications?.some(n => n.type === "webhook") || false, + webhookUrl: monitor?.notifications?.find(n => n.type === "webhook")?.url || "", + }); + + const testNotificationButtonStyle = { + textDecoration: 'underline', + color: '#344054', + textTransform: 'none', + padding: '0 !important', + margin: 0, + fontSize: '0.9rem', + fontWeight: 'normal', + backgroundColor: 'transparent !important', + '&:hover': { + backgroundColor: 'transparent !important', + textDecoration: 'underline' + }, + '&.Mui-disabled': { + backgroundColor: 'transparent !important' + }, + minWidth: '0 !important', + boxShadow: 'none !important', + border: 'none !important' + }; + + const handleChangeTab = (event, newValue) => { + setTabValue(newValue); + }; + + const handleIntegrationChange = (type, checked) => { + setIntegrations(prev => ({ + ...prev, + [type]: checked + })); + }; + + const handleInputChange = (type, value) => { + setIntegrations(prev => ({ + ...prev, + [type]: value + })); + }; + + const handleTestNotification = (type) => { + console.log(`Testing ${type} notification`); + // Here you would implement the actual test notification functionality + }; + + const handleSave = () => { + // Create notifications array based on selected integrations + const notifications = [...(monitor?.notifications || [])]; + + // Filter out existing integrations that will be updated + const existingTypes = ["slack", "discord", "telegram", "webhook"]; + const filteredNotifications = notifications.filter( + notification => !existingTypes.includes(notification.type) + ); + + // Add selected integrations + if (integrations.slack) { + filteredNotifications.push({ + type: "slack", + webhook: integrations.slackWebhook + }); + } + + if (integrations.discord) { + filteredNotifications.push({ + type: "discord", + webhook: integrations.discordWebhook + }); + } + + if (integrations.telegram) { + filteredNotifications.push({ + type: "telegram", + token: integrations.telegramToken, + chatId: integrations.telegramChatId + }); + } + + if (integrations.webhook) { + filteredNotifications.push({ + type: "webhook", + url: integrations.webhookUrl + }); + } + + // Update monitor with new notifications + setMonitor(prev => ({ + ...prev, + notifications: filteredNotifications + })); + + onClose(); + }; + + return ( + + + + + {/* Left sidebar with tabs */} + + + Add or edit notifications + + + + + + + + + + + {/* Right side content */} + + {/* Slack Tab */} + + Slack + + To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here. + + + + handleIntegrationChange('slack', e.target.checked)} + /> + + + + Webhook URL + handleInputChange('slackWebhook', e.target.value)} + disabled={!integrations.slack} + /> + + + + + + + + {/* Discord Tab */} + + Discord + + To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature. + + + + handleIntegrationChange('discord', e.target.checked)} + /> + + + + Discord Webhook URL + handleInputChange('discordWebhook', e.target.value)} + disabled={!integrations.discord} + /> + + + + + + + + {/* Telegram Tab */} + + Telegram + + 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. + + + + handleIntegrationChange('telegram', e.target.checked)} + /> + + + + Your bot token + handleInputChange('telegramToken', e.target.value)} + disabled={!integrations.telegram} + /> + + + + Your Chat ID + handleInputChange('telegramChatId', e.target.value)} + disabled={!integrations.telegram} + /> + + + + + + + + {/* Webhooks Tab */} + + Webhooks + + You can set up a custom webhook to receive notifications when incidents occur. + + + + handleIntegrationChange('webhook', e.target.checked)} + /> + + + + Webhook URL + handleInputChange('webhookUrl', e.target.value)} + disabled={!integrations.webhook} + /> + + + + + + + + + + + + + + ); +}; + +export default NotificationIntegrationModal; \ No newline at end of file From 1105a3808036461d2138108f7885bbb1321f5c3c Mon Sep 17 00:00:00 2001 From: Skorpios Date: Tue, 4 Mar 2025 15:56:09 -0800 Subject: [PATCH 02/20] Moved component to the regular components dir. --- .../NotificationIntegrationModal.jsx | 28 ++++++++++++------- src/Pages/Uptime/Create/index.jsx | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) rename src/{Pages/Uptime/Details => }/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx (95%) diff --git a/src/Pages/Uptime/Details/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx similarity index 95% rename from src/Pages/Uptime/Details/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx rename to src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index eca6a78d0..ae6cdc28b 100644 --- a/src/Pages/Uptime/Details/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -13,8 +13,8 @@ import { Divider } from "@mui/material"; import { useTheme } from "@emotion/react"; -import TextInput from "../../../../../../src/Components/Inputs/TextInput"; -import Checkbox from "../../../../../../src/Components/Inputs/Checkbox"; +import TextInput from "../Inputs/TextInput"; +import Checkbox from "../Inputs/Checkbox"; // Tab Panel component function TabPanel({ children, value, index, ...other }) { @@ -96,20 +96,18 @@ const NotificationIntegrationModal = ({ const handleTestNotification = (type) => { console.log(`Testing ${type} notification`); - // Here you would implement the actual test notification functionality + //implement the test notification functionality }; const handleSave = () => { - // Create notifications array based on selected integrations + //notifications array for selected integrations const notifications = [...(monitor?.notifications || [])]; - // Filter out existing integrations that will be updated const existingTypes = ["slack", "discord", "telegram", "webhook"]; const filteredNotifications = notifications.filter( notification => !existingTypes.includes(notification.type) ); - // Add selected integrations if (integrations.slack) { filteredNotifications.push({ type: "slack", @@ -157,13 +155,14 @@ const NotificationIntegrationModal = ({ sx={{ '& .MuiDialog-paper': { backgroundColor: theme.palette.primary.main, - color: '#344054' + color: '#344054', + maxWidth: '775px' } }} > - + {/* Left sidebar with tabs */} - + diff --git a/src/Pages/Uptime/Create/index.jsx b/src/Pages/Uptime/Create/index.jsx index b9bb7eb8f..ebafa3a1f 100644 --- a/src/Pages/Uptime/Create/index.jsx +++ b/src/Pages/Uptime/Create/index.jsx @@ -23,7 +23,7 @@ import Radio from "../../../Components/Inputs/Radio"; import Checkbox from "../../../Components/Inputs/Checkbox"; import Select from "../../../Components/Inputs/Select"; import ConfigBox from "../../../Components/ConfigBox"; -import NotificationIntegrationModal from "../Details/Components/NotificationIntegrationModal/NotificationIntegrationModal"; +import NotificationIntegrationModal from "../../../Components/NotificationIntegrationModal/NotificationIntegrationModal"; const CreateMonitor = () => { const MS_PER_MINUTE = 60000; const SELECT_VALUES = [ From 055799a1356aeadd0426fe25cab249738bbe60c1 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Tue, 4 Mar 2025 15:57:30 -0800 Subject: [PATCH 03/20] Used theme values for consistency instead of hardcoded values for padding. --- .../NotificationIntegrationModal.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index ae6cdc28b..cc326e0dc 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -18,6 +18,8 @@ import Checkbox from "../Inputs/Checkbox"; // Tab Panel component function TabPanel({ children, value, index, ...other }) { + const theme = useTheme(); + return (
{value === index && ( - + {children} )} From 5e730acd478b15f059020ebc75708bd34edd05dd Mon Sep 17 00:00:00 2001 From: Skorpios Date: Thu, 6 Mar 2025 17:16:45 -0800 Subject: [PATCH 04/20] Declared variants for the vertical version of tabs in the theme. --- .../NotificationIntegrationModal.jsx | 36 +----- src/Utils/Theme/globalTheme.js | 104 ++++++++++++------ 2 files changed, 74 insertions(+), 66 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index cc326e0dc..1392d6edf 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -182,39 +182,11 @@ const NotificationIntegrationModal = ({ value={tabValue} onChange={handleChangeTab} aria-label="Notification tabs" - sx={{ - backgroundColor: theme.palette.primary.main, - '& .MuiTab-root': { - alignItems: 'flex-start', - px: 2, - fontSize: '0.9rem', - color: theme.palette.primary.contrastText, - backgroundColor: theme.palette.primary.main, - border: 'none', - borderBottom: 'none', - borderRight: 'none', - '&.Mui-selected': { - color: theme.palette.primary.contrastText, - backgroundColor: theme.palette.tertiary.main, // Match the hover background color - opacity: 1, - border: 'none', - borderBottom: 'none', - borderRight: 'none' - }, - '&:hover': { - backgroundColor: theme.palette.tertiary.main, - border: 'none' - } - }, - '& .MuiTabs-indicator': { - backgroundColor: 'transparent' - } - }} > - - - - + + + + diff --git a/src/Utils/Theme/globalTheme.js b/src/Utils/Theme/globalTheme.js index 3598af675..7f347d29f 100644 --- a/src/Utils/Theme/globalTheme.js +++ b/src/Utils/Theme/globalTheme.js @@ -328,35 +328,61 @@ const baseTheme = (palette) => ({ }, MuiTab: { styleOverrides: { - root: ({ theme }) => ({ - fontSize: 13, - color: theme.palette.tertiary.contrastText, - backgroundColor: theme.palette.tertiary.main, - textTransform: "none", - minWidth: "fit-content", - paddingY: theme.spacing(6), - fontWeight: 400, - borderBottom: "2px solid transparent", - borderRight: `1px solid ${theme.palette.primary.lowContrast}`, - "&:first-of-type": { borderTopLeftRadius: "8px" }, - "&:last-child": { borderTopRightRadius: "8px", borderRight: 0 }, - "&:focus-visible": { - color: theme.palette.primary.contrastText, - borderColor: theme.palette.tertiary.contrastText, - borderRightColor: theme.palette.primary.lowContrast, - }, - "&.Mui-selected": { - backgroundColor: theme.palette.secondary.main, - color: theme.palette.secondary.contrastText, - borderColor: theme.palette.secondary.contrastText, - borderRightColor: theme.palette.primary.lowContrast, - }, - "&:hover": { - borderColor: theme.palette.primary.lowContrast, - }, - }), + root: ({ theme }) => ({ + fontSize: 13, + color: theme.palette.tertiary.contrastText, + backgroundColor: theme.palette.tertiary.main, + textTransform: "none", + minWidth: "fit-content", + paddingY: theme.spacing(6), + fontWeight: 400, + borderBottom: "2px solid transparent", + borderRight: `1px solid ${theme.palette.primary.lowContrast}`, + "&:first-of-type": { borderTopLeftRadius: "8px" }, + "&:last-child": { borderTopRightRadius: "8px", borderRight: 0 }, + "&:focus-visible": { + color: theme.palette.primary.contrastText, + borderColor: theme.palette.tertiary.contrastText, + borderRightColor: theme.palette.primary.lowContrast, + }, + "&.Mui-selected": { + backgroundColor: theme.palette.secondary.main, + color: theme.palette.secondary.contrastText, + borderColor: theme.palette.secondary.contrastText, + borderRightColor: theme.palette.primary.lowContrast, + }, + "&:hover": { + borderColor: theme.palette.primary.lowContrast, + }, + }), }, - }, + variants: [ + { + props: { orientation: 'vertical' }, + style: ({ theme }) => ({ + alignItems: 'flex-start', + padding: theme.spacing(2), + color: theme.palette.primary.contrastText, + backgroundColor: theme.palette.primary.main, + border: 'none', + borderBottom: 'none', + borderRight: 'none', + '&.Mui-selected': { + color: theme.palette.primary.contrastText, + backgroundColor: theme.palette.tertiary.main, + opacity: 1, + border: 'none', + borderBottom: 'none', + borderRight: 'none' + }, + '&:hover': { + backgroundColor: theme.palette.tertiary.main, + border: 'none' + } + }), + }, + ], + }, MuiSvgIcon: { styleOverrides: { root: ({ theme }) => ({ @@ -366,13 +392,23 @@ const baseTheme = (palette) => ({ }, MuiTabs: { styleOverrides: { - root: ({ theme }) => ({ - "& .MuiTabs-indicator": { - backgroundColor: theme.palette.tertiary.contrastText, - }, - }), + root: ({ theme }) => ({ + "& .MuiTabs-indicator": { + backgroundColor: theme.palette.tertiary.contrastText, + }, + }), }, - }, + variants: [ + { + props: { orientation: 'vertical' }, + style: { + "& .MuiTabs-indicator": { + display: 'none', + } + }, + }, + ], + }, MuiSwitch: { styleOverrides: { root: ({ theme }) => ({ From 4736f4f301b56a11afd4e7daf4558a74533a22b7 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Thu, 6 Mar 2025 17:46:43 -0800 Subject: [PATCH 05/20] Got rid of button overrides and made a variant for text button. --- .../NotificationIntegrationModal.jsx | 25 ----------------- src/Utils/Theme/globalTheme.js | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index 1392d6edf..8716550f5 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -56,27 +56,6 @@ const NotificationIntegrationModal = ({ webhook: monitor?.notifications?.some(n => n.type === "webhook") || false, webhookUrl: monitor?.notifications?.find(n => n.type === "webhook")?.url || "", }); - - const testNotificationButtonStyle = { - textDecoration: 'underline', - color: '#344054', - textTransform: 'none', - padding: '0 !important', - margin: 0, - fontSize: '0.9rem', - fontWeight: 'normal', - backgroundColor: 'transparent !important', - '&:hover': { - backgroundColor: 'transparent !important', - textDecoration: 'underline' - }, - '&.Mui-disabled': { - backgroundColor: 'transparent !important' - }, - minWidth: '0 !important', - boxShadow: 'none !important', - border: 'none !important' - }; const handleChangeTab = (event, newValue) => { setTabValue(newValue); @@ -226,7 +205,6 @@ const NotificationIntegrationModal = ({ color="info" onClick={() => handleTestNotification('slack')} disabled={!integrations.slack || !integrations.slackWebhook} - sx={testNotificationButtonStyle} > Test notification @@ -267,7 +245,6 @@ const NotificationIntegrationModal = ({ color="info" onClick={() => handleTestNotification('discord')} disabled={!integrations.discord || !integrations.discordWebhook} - sx={testNotificationButtonStyle} > Test notification @@ -320,7 +297,6 @@ const NotificationIntegrationModal = ({ color="info" onClick={() => handleTestNotification('telegram')} disabled={!integrations.telegram || !integrations.telegramToken || !integrations.telegramChatId} - sx={testNotificationButtonStyle} > Test notification @@ -361,7 +337,6 @@ const NotificationIntegrationModal = ({ color="info" onClick={() => handleTestNotification('webhook')} disabled={!integrations.webhook || !integrations.webhookUrl} - sx={testNotificationButtonStyle} > Test notification diff --git a/src/Utils/Theme/globalTheme.js b/src/Utils/Theme/globalTheme.js index 7f347d29f..89ad85c2b 100644 --- a/src/Utils/Theme/globalTheme.js +++ b/src/Utils/Theme/globalTheme.js @@ -117,6 +117,33 @@ const baseTheme = (palette) => ({ color: `${theme.palette.secondary.contrastText} !important`, }, }, + + { + props: { variant: 'text', color: 'info' }, + style: { + textDecoration: 'underline', + color: '#344054', + padding: 0, + margin: 0, + fontSize: '0.9rem', + fontWeight: 'normal', + backgroundColor: 'transparent', + '&:hover': { + backgroundColor: 'transparent', + textDecoration: 'underline' + }, + "&.Mui-disabled": { + backgroundColor: theme.palette.secondary.main, + color: theme.palette.primary.contrastText, + "&.MuiButton-text": { + backgroundColor: 'transparent' + } + }, + minWidth: 0, + boxShadow: 'none', + border: 'none' + }, + }, ], height: 34, fontWeight: 400, From a296a70bcd9cafa403cec6a9ac144dbcecfd5cab Mon Sep 17 00:00:00 2001 From: Skorpios Date: Thu, 6 Mar 2025 17:48:46 -0800 Subject: [PATCH 06/20] adjust padding with theme spacing for consistency. --- .../NotificationIntegrationModal.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index 8716550f5..0a70b6448 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -170,7 +170,7 @@ const NotificationIntegrationModal = ({ {/* Right side content */} - + {/* Slack Tab */} Slack From 5fff398a2590ddb0f39333161a101953c1033c36 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Thu, 6 Mar 2025 17:56:30 -0800 Subject: [PATCH 07/20] Got rid of all overridden styles. --- .../NotificationIntegrationModal.jsx | 136 ++++++++++++------ 1 file changed, 93 insertions(+), 43 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index 0a70b6448..1015667f9 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -135,13 +135,10 @@ const NotificationIntegrationModal = ({ maxWidth="md" sx={{ '& .MuiDialog-paper': { - backgroundColor: theme.palette.primary.main, - color: '#344054', maxWidth: '775px' } }} > - {/* Left sidebar with tabs */} @@ -149,10 +146,15 @@ const NotificationIntegrationModal = ({ borderRight: 1, borderColor: 'divider', minWidth: '200px', - pr: 20 + pr: theme.spacing(10) }}> - - Add or edit notifications + + Add or edit notifications {/* Right side content */} - + {/* Slack Tab */} - Slack - + Slack + To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here. - - handleIntegrationChange('slack', e.target.checked)} - /> - + + handleIntegrationChange('slack', e.target.checked)} + /> + - - Webhook URL + + Webhook URL - + - - - - {/* Discord Tab */} - - Discord - - To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord's incoming Webhooks feature. - - - - handleIntegrationChange('discord', e.target.checked)} - /> - - - + }}>{type.label} Discord Webhook URL - handleInputChange('discordWebhook', e.target.value)} - disabled={!integrations.discord} - /> - - - - - - - - {/* Telegram Tab */} - - Telegram - - 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. - - - - handleIntegrationChange('telegram', e.target.checked)} - /> - - - - Your bot token - handleInputChange('telegramToken', e.target.value)} - disabled={!integrations.telegram} - /> - - - - Your Chat ID - handleInputChange('telegramChatId', e.target.value)} - disabled={!integrations.telegram} - /> - - - - - - - - {/* Webhooks Tab */} - - Webhooks - - You can set up a custom webhook to receive notifications when incidents occur. - - - - handleIntegrationChange('webhook', e.target.checked)} - /> - - - - Webhook URL - handleInputChange('webhookUrl', e.target.value)} - disabled={!integrations.webhook} - /> - - - - - - + mt: theme.spacing(0.5), + mb: theme.spacing(1.5), + color: theme.palette.primary.contrastTextTertiary + }}> + {type.description} + + + + handleIntegrationChange(type.id, e.target.checked)} + /> + + + {type.fields.map(field => { + const fieldKey = `${type.id}${field.id.charAt(0).toUpperCase() + field.id.slice(1)}`; + + return ( + + {field.label} + handleInputChange(fieldKey, e.target.value)} + disabled={!integrations[type.id]} + /> + + ); + })} + + + + + + ))} From 3ac56c1ea78e33bb041eee4e1ab61cc87cf9af91 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 13:01:28 -0800 Subject: [PATCH 11/20] Made a separate tab component. --- .../NotificationIntegrationModal.jsx | 68 ++----------- .../TabComponent.jsx | 97 +++++++++++++++++++ 2 files changed, 106 insertions(+), 59 deletions(-) create mode 100644 src/Components/NotificationIntegrationModal/TabComponent.jsx diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index a2c00c882..d8955f18e 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -10,9 +10,8 @@ import { Tab } from "@mui/material"; import { useTheme } from "@emotion/react"; -import TextInput from "../Inputs/TextInput"; -import Checkbox from "../Inputs/Checkbox"; import TabPanel from "./TabPanel"; +import TabComponent from "./TabComponent"; // Configuration for notification tabs const NOTIFICATION_TYPES = [ @@ -205,7 +204,7 @@ const NotificationIntegrationModal = ({ onChange={handleChangeTab} aria-label="Notification tabs" > - {notificationTypes.map((type, index) => ( + {notificationTypes.map((type) => ( ))} @@ -215,62 +214,13 @@ const NotificationIntegrationModal = ({ {notificationTypes.map((type, index) => ( - {type.label} - - {type.description} - - - - handleIntegrationChange(type.id, e.target.checked)} - /> - - - {type.fields.map(field => { - const fieldKey = `${type.id}${field.id.charAt(0).toUpperCase() + field.id.slice(1)}`; - - return ( - - {field.label} - handleInputChange(fieldKey, e.target.value)} - disabled={!integrations[type.id]} - /> - - ); - })} - - - - + ))} diff --git a/src/Components/NotificationIntegrationModal/TabComponent.jsx b/src/Components/NotificationIntegrationModal/TabComponent.jsx new file mode 100644 index 000000000..f9cf6ab53 --- /dev/null +++ b/src/Components/NotificationIntegrationModal/TabComponent.jsx @@ -0,0 +1,97 @@ +import React from "react"; +import { + Typography, + Box, + Button +} from "@mui/material"; +import { useTheme } from "@emotion/react"; +import TextInput from "../../../src/Components/Inputs/TextInput"; +import Checkbox from "../../../src/Components/Inputs/Checkbox"; +const TabComponent = ({ + type, + integrations, + handleIntegrationChange, + handleInputChange, + handleTestNotification +}) => { + const theme = useTheme(); + + // Helper to get the field state key (e.g., slackWebhook, telegramToken) + const getFieldKey = (typeId, fieldId) => { + return `${typeId}${fieldId.charAt(0).toUpperCase() + fieldId.slice(1)}`; + }; + + // Check if all fields have values to enable test button + const areAllFieldsFilled = () => { + return type.fields.every(field => { + const fieldKey = getFieldKey(type.id, field.id); + return integrations[fieldKey]; + }); + }; + + return ( + <> + + {type.label} + + + + {type.description} + + + + handleIntegrationChange(type.id, e.target.checked)} + /> + + + {type.fields.map(field => { + const fieldKey = getFieldKey(type.id, field.id); + + return ( + + + {field.label} + + + handleInputChange(fieldKey, e.target.value)} + disabled={!integrations[type.id]} + /> + + ); + })} + + + + + + ); +}; + +export default TabComponent; \ No newline at end of file From 94045f1164ea3d85d8a41ee34301ac018ff3da93 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 13:56:51 -0800 Subject: [PATCH 12/20] Updated font sizes and colors to match theme values. --- src/Utils/Theme/globalTheme.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Utils/Theme/globalTheme.js b/src/Utils/Theme/globalTheme.js index 89ad85c2b..dec8c5913 100644 --- a/src/Utils/Theme/globalTheme.js +++ b/src/Utils/Theme/globalTheme.js @@ -122,11 +122,11 @@ const baseTheme = (palette) => ({ props: { variant: 'text', color: 'info' }, style: { textDecoration: 'underline', - color: '#344054', + color: theme.palette.text.primary, padding: 0, margin: 0, - fontSize: '0.9rem', - fontWeight: 'normal', + fontSize: typographyLevels.m, + fontWeight: theme.typography.body2.fontWeight, backgroundColor: 'transparent', '&:hover': { backgroundColor: 'transparent', From 71763f4b6679d0c1c44530a7b2e56af77c26698e Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 14:40:20 -0800 Subject: [PATCH 13/20] Adjusted padding and borders for a more aesthetic look and feel for the vertical tabs. --- src/Utils/Theme/globalTheme.js | 51 +++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/Utils/Theme/globalTheme.js b/src/Utils/Theme/globalTheme.js index dec8c5913..1a68cdd70 100644 --- a/src/Utils/Theme/globalTheme.js +++ b/src/Utils/Theme/globalTheme.js @@ -384,31 +384,38 @@ const baseTheme = (palette) => ({ }), }, variants: [ - { - props: { orientation: 'vertical' }, - style: ({ theme }) => ({ - alignItems: 'flex-start', - padding: theme.spacing(2), - color: theme.palette.primary.contrastText, - backgroundColor: theme.palette.primary.main, - border: 'none', - borderBottom: 'none', - borderRight: 'none', - '&.Mui-selected': { + { + props: { orientation: 'vertical' }, + style: ({ theme }) => ({ + alignItems: 'flex-start', + padding: `${theme.spacing(1)}px ${theme.spacing(2)}px ${theme.spacing(1)}px ${theme.spacing(6)}px`, + minHeight: theme.spacing(12), color: theme.palette.primary.contrastText, - backgroundColor: theme.palette.tertiary.main, - opacity: 1, + backgroundColor: theme.palette.primary.main, border: 'none', borderBottom: 'none', - borderRight: 'none' - }, - '&:hover': { - backgroundColor: theme.palette.tertiary.main, - border: 'none' - } - }), - }, - ], + borderRight: 'none', + borderRadius: theme.shape.borderRadius * 3, + margin: `${theme.spacing(1)}px ${theme.spacing(2)}px`, + '&.Mui-selected': { + color: theme.palette.primary.contrastText, + backgroundColor: theme.palette.tertiary.main, + opacity: 1, + border: 'none', + borderBottom: 'none', + borderRight: 'none', + borderRadius: theme.shape.borderRadius * 3, + minHeight: theme.spacing(14) + }, + '&:hover': { + backgroundColor: theme.palette.tertiary.main, + border: 'none', + borderRadius: theme.shape.borderRadius * 3, + minHeight: theme.spacing(14) + } + }), + }, + ], }, MuiSvgIcon: { styleOverrides: { From 2a54d2ce165cc393a5033b74627e45027651980f Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 14:54:52 -0800 Subject: [PATCH 14/20] Fix spacing, borders, and border radius for style overrides to match theme values. --- src/Utils/Theme/globalTheme.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Utils/Theme/globalTheme.js b/src/Utils/Theme/globalTheme.js index 1a68cdd70..e3363daab 100644 --- a/src/Utils/Theme/globalTheme.js +++ b/src/Utils/Theme/globalTheme.js @@ -356,17 +356,17 @@ const baseTheme = (palette) => ({ MuiTab: { styleOverrides: { root: ({ theme }) => ({ - fontSize: 13, + fontSize: theme.typography.fontSize - 1, color: theme.palette.tertiary.contrastText, backgroundColor: theme.palette.tertiary.main, textTransform: "none", minWidth: "fit-content", - paddingY: theme.spacing(6), + padding: `${theme.spacing(6)}px ${theme.spacing(4)}px`, fontWeight: 400, - borderBottom: "2px solid transparent", - borderRight: `1px solid ${theme.palette.primary.lowContrast}`, - "&:first-of-type": { borderTopLeftRadius: "8px" }, - "&:last-child": { borderTopRightRadius: "8px", borderRight: 0 }, + borderBottom: `${theme.shape.borderThick}px solid transparent`, + borderRight: `${theme.shape.borderRadius / 2}px solid ${theme.palette.primary.lowContrast}`, + "&:first-of-type": { borderTopLeftRadius: theme.shape.borderRadius * 4 }, + "&:last-child": { borderTopRightRadius: theme.shape.borderRadius * 4, borderRight: 0 }, "&:focus-visible": { color: theme.palette.primary.contrastText, borderColor: theme.palette.tertiary.contrastText, From 25ff7abe7f1ad7542995a0ecefadb29efc518a93 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 16:44:52 -0800 Subject: [PATCH 15/20] refactored all the hardcoded absolute dimension values and made them into relative values that reference the theme. --- .../NotificationIntegrationModal.jsx | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index d8955f18e..2522105a3 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -175,24 +175,30 @@ const NotificationIntegrationModal = ({ maxWidth="md" sx={{ '& .MuiDialog-paper': { - maxWidth: '775px' + width: `calc(90% - ${theme.spacing(40)})`, + maxWidth: theme.breakpoints.values.md } }} > - + {/* Left sidebar with tabs */} Add or edit notifications @@ -205,13 +211,22 @@ const NotificationIntegrationModal = ({ aria-label="Notification tabs" > {notificationTypes.map((type) => ( - + ))} {/* Right side content */} - + {notificationTypes.map((type, index) => ( Save From 99ec5be86545f84a49cb64c7f9360ec0a777a332 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 16:59:53 -0800 Subject: [PATCH 16/20] Added proptypes and jsdocs to the tabpanel. --- .../NotificationIntegrationModal.jsx | 4 ++-- .../NotificationIntegrationModal/TabPanel.jsx | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index 2522105a3..16efe77d8 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -175,8 +175,8 @@ const NotificationIntegrationModal = ({ maxWidth="md" sx={{ '& .MuiDialog-paper': { - width: `calc(90% - ${theme.spacing(40)})`, - maxWidth: theme.breakpoints.values.md + width: `calc(80% - ${theme.spacing(40)})`, + maxWidth: `${theme.breakpoints.values.md - 70}px` } }} > diff --git a/src/Components/NotificationIntegrationModal/TabPanel.jsx b/src/Components/NotificationIntegrationModal/TabPanel.jsx index 6299b56e9..a9252e710 100644 --- a/src/Components/NotificationIntegrationModal/TabPanel.jsx +++ b/src/Components/NotificationIntegrationModal/TabPanel.jsx @@ -1,7 +1,19 @@ import React from "react"; +import PropTypes from "prop-types"; import { Box } from "@mui/material"; import { useTheme } from "@emotion/react"; +/** + * TabPanel component that displays content for the selected tab. + * + * @component + * @param {Object} props - The component props. + * @param {React.ReactNode} props.children - The content to be displayed when this tab panel is selected. + * @param {number} props.value - The currently selected tab value. + * @param {number} props.index - The index of this specific tab panel. + * @param {Object} props.other - Any additional props to be spread to the root element. + * @returns {React.ReactElement|null} The rendered tab panel or null if not selected. + */ function TabPanel({ children, value, index, ...other }) { const theme = useTheme(); @@ -22,4 +34,13 @@ function TabPanel({ children, value, index, ...other }) { ); } +TabPanel.propTypes = { + + children: PropTypes.node, + + index: PropTypes.number.isRequired, + + value: PropTypes.number.isRequired +}; + export default TabPanel; \ No newline at end of file From d335cfb4eeabd2478891cbb9fd3f7c7994a216a5 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 17:13:20 -0800 Subject: [PATCH 17/20] Got rid of unnecessary rerenders by memoizing the integrationstate function. --- .../NotificationIntegrationModal.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index 16efe77d8..81f2baec0 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useMemo } from "react"; import { Dialog, DialogContent, @@ -86,8 +86,8 @@ const NotificationIntegrationModal = ({ const theme = useTheme(); const [tabValue, setTabValue] = useState(0); - // Initialize integrations state based on available notification types - const initializeIntegrationsState = () => { + // Memoized function to initialize integrations state + const initialIntegrationsState = useMemo(() => { const state = {}; notificationTypes.forEach(type => { @@ -102,9 +102,9 @@ const NotificationIntegrationModal = ({ }); return state; - }; + }, [monitor, notificationTypes]); // Only recompute when these dependencies change - const [integrations, setIntegrations] = useState(initializeIntegrationsState()); + const [integrations, setIntegrations] = useState(initialIntegrationsState); const handleChangeTab = (event, newValue) => { setTabValue(newValue); From 93462d7ba662c6aea1424decead23f15ded8f45b Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sat, 8 Mar 2025 17:57:27 -0800 Subject: [PATCH 18/20] Changed all user facing strings to use the i18n implementation. --- .../NotificationIntegrationModal.jsx | 37 +++++++++++++++++-- .../TabComponent.jsx | 7 +++- src/locales/gb.json | 35 +++++++++++++++++- 3 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index 81f2baec0..cd5a96aa2 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -1,4 +1,5 @@ import { useState, useMemo } from "react"; +import { useTranslation } from "react-i18next"; import { Dialog, DialogContent, @@ -18,12 +19,16 @@ const NOTIFICATION_TYPES = [ { id: 'slack', label: 'Slack', + labelKey: 'notifications.slack.label', description: 'To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.', + descriptionKey: 'notifications.slack.description', fields: [ { id: 'webhook', label: 'Webhook URL', + labelKey: 'notifications.slack.webhookLabel', placeholder: 'https://hooks.slack.com/services/...', + placeholderKey: 'notifications.slack.webhookPlaceholder', type: 'text' } ] @@ -31,12 +36,16 @@ const NOTIFICATION_TYPES = [ { id: 'discord', label: 'Discord', + labelKey: 'notifications.discord.label', description: 'To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord\'s incoming Webhooks feature.', + descriptionKey: 'notifications.discord.description', fields: [ { id: 'webhook', label: 'Discord Webhook URL', + labelKey: 'notifications.discord.webhookLabel', placeholder: 'https://discord.com/api/webhooks/...', + placeholderKey: 'notifications.discord.webhookPlaceholder', type: 'text' } ] @@ -44,18 +53,24 @@ const NOTIFICATION_TYPES = [ { id: 'telegram', label: 'Telegram', + labelKey: 'notifications.telegram.label', 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.', + descriptionKey: 'notifications.telegram.description', fields: [ { id: 'token', label: 'Your bot token', + labelKey: 'notifications.telegram.tokenLabel', placeholder: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', + placeholderKey: 'notifications.telegram.tokenPlaceholder', type: 'text' }, { id: 'chatId', label: 'Your Chat ID', + labelKey: 'notifications.telegram.chatIdLabel', placeholder: '-1001234567890', + placeholderKey: 'notifications.telegram.chatIdPlaceholder', type: 'text' } ] @@ -63,12 +78,16 @@ const NOTIFICATION_TYPES = [ { id: 'webhook', label: 'Webhooks', + labelKey: 'notifications.webhook.label', description: 'You can set up a custom webhook to receive notifications when incidents occur.', + descriptionKey: 'notifications.webhook.description', fields: [ { id: 'url', label: 'Webhook URL', + labelKey: 'notifications.webhook.urlLabel', placeholder: 'https://your-server.com/webhook', + placeholderKey: 'notifications.webhook.urlPlaceholder', type: 'text' } ] @@ -83,6 +102,7 @@ const NotificationIntegrationModal = ({ // Optional prop to configure available notification types notificationTypes = NOTIFICATION_TYPES }) => { + const { t } = useTranslation(); const theme = useTheme(); const [tabValue, setTabValue] = useState(0); @@ -200,7 +220,7 @@ const NotificationIntegrationModal = ({ color: theme.palette.primary.contrastTextSecondary, pl: theme.spacing(4) }}> - Add or edit notifications + {t('notifications.addOrEditNotifications', 'Add or edit notifications')} ( @@ -230,7 +250,16 @@ const NotificationIntegrationModal = ({ {notificationTypes.map((type, index) => ( ({ + ...field, + label: t(field.labelKey, field.label), + placeholder: t(field.placeholderKey, field.placeholder) + })) + }} integrations={integrations} handleIntegrationChange={handleIntegrationChange} handleInputChange={handleInputChange} @@ -258,7 +287,7 @@ const NotificationIntegrationModal = ({ px: theme.spacing(8) }} > - Save + {t('common.save', 'Save')} diff --git a/src/Components/NotificationIntegrationModal/TabComponent.jsx b/src/Components/NotificationIntegrationModal/TabComponent.jsx index f9cf6ab53..89216a8c1 100644 --- a/src/Components/NotificationIntegrationModal/TabComponent.jsx +++ b/src/Components/NotificationIntegrationModal/TabComponent.jsx @@ -4,9 +4,11 @@ import { Box, Button } from "@mui/material"; +import { useTranslation } from "react-i18next"; import { useTheme } from "@emotion/react"; import TextInput from "../../../src/Components/Inputs/TextInput"; import Checkbox from "../../../src/Components/Inputs/Checkbox"; + const TabComponent = ({ type, integrations, @@ -15,6 +17,7 @@ const TabComponent = ({ handleTestNotification }) => { const theme = useTheme(); + const { t } = useTranslation(); // Helper to get the field state key (e.g., slackWebhook, telegramToken) const getFieldKey = (typeId, fieldId) => { @@ -49,7 +52,7 @@ const TabComponent = ({ handleIntegrationChange(type.id, e.target.checked)} /> @@ -87,7 +90,7 @@ const TabComponent = ({ onClick={() => handleTestNotification(type.id)} disabled={!integrations[type.id] || !areAllFieldsFilled()} > - Test notification + {t('notifications.testNotification')} diff --git a/src/locales/gb.json b/src/locales/gb.json index cf7711fa8..9756f8a9d 100644 --- a/src/locales/gb.json +++ b/src/locales/gb.json @@ -107,5 +107,38 @@ "settingsDemoMonitorsAdded": "Successfully added demo monitors", "settingsFailedToAddDemoMonitors": "Failed to add demo monitors", "settingsMonitorsDeleted": "Successfully deleted all monitors", - "settingsFailedToDeleteMonitors": "Failed to delete all monitors" + "settingsFailedToDeleteMonitors": "Failed to delete all monitors", + + "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/..." + }, + "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/..." + }, + "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" + }, + "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" + } + } + } From 78e46ecc5aa7ab922972343e610ad63a97fd24b9 Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sun, 9 Mar 2025 20:21:10 -0700 Subject: [PATCH 19/20] Use i18n for front facing strings. --- .../NotificationIntegrationModal.jsx | 174 ++++++++---------- 1 file changed, 75 insertions(+), 99 deletions(-) diff --git a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx index cd5a96aa2..30587833a 100644 --- a/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx +++ b/src/Components/NotificationIntegrationModal/NotificationIntegrationModal.jsx @@ -14,103 +14,88 @@ import { useTheme } from "@emotion/react"; import TabPanel from "./TabPanel"; import TabComponent from "./TabComponent"; -// Configuration for notification tabs -const NOTIFICATION_TYPES = [ - { - id: 'slack', - label: 'Slack', - labelKey: 'notifications.slack.label', - description: 'To enable Slack notifications, create a Slack app and enable incoming webhooks. After that, simply provide the webhook URL here.', - descriptionKey: 'notifications.slack.description', - fields: [ - { - id: 'webhook', - label: 'Webhook URL', - labelKey: 'notifications.slack.webhookLabel', - placeholder: 'https://hooks.slack.com/services/...', - placeholderKey: 'notifications.slack.webhookPlaceholder', - type: 'text' - } - ] - }, - { - id: 'discord', - label: 'Discord', - labelKey: 'notifications.discord.label', - description: 'To send data to a Discord channel from Checkmate via Discord notifications using webhooks, you can use Discord\'s incoming Webhooks feature.', - descriptionKey: 'notifications.discord.description', - fields: [ - { - id: 'webhook', - label: 'Discord Webhook URL', - labelKey: 'notifications.discord.webhookLabel', - placeholder: 'https://discord.com/api/webhooks/...', - placeholderKey: 'notifications.discord.webhookPlaceholder', - type: 'text' - } - ] - }, - { - id: 'telegram', - label: 'Telegram', - labelKey: 'notifications.telegram.label', - 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.', - descriptionKey: 'notifications.telegram.description', - fields: [ - { - id: 'token', - label: 'Your bot token', - labelKey: 'notifications.telegram.tokenLabel', - placeholder: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', - placeholderKey: 'notifications.telegram.tokenPlaceholder', - type: 'text' - }, - { - id: 'chatId', - label: 'Your Chat ID', - labelKey: 'notifications.telegram.chatIdLabel', - placeholder: '-1001234567890', - placeholderKey: 'notifications.telegram.chatIdPlaceholder', - type: 'text' - } - ] - }, - { - id: 'webhook', - label: 'Webhooks', - labelKey: 'notifications.webhook.label', - description: 'You can set up a custom webhook to receive notifications when incidents occur.', - descriptionKey: 'notifications.webhook.description', - fields: [ - { - id: 'url', - label: 'Webhook URL', - labelKey: 'notifications.webhook.urlLabel', - placeholder: 'https://your-server.com/webhook', - placeholderKey: 'notifications.webhook.urlPlaceholder', - type: 'text' - } - ] - } -]; - const NotificationIntegrationModal = ({ open, onClose, monitor, setMonitor, // Optional prop to configure available notification types - notificationTypes = NOTIFICATION_TYPES + notificationTypes = null }) => { const { t } = useTranslation(); const theme = useTheme(); const [tabValue, setTabValue] = useState(0); + // Define notification types + const DEFAULT_NOTIFICATION_TYPES = [ + { + id: 'slack', + label: t('notifications.slack.label'), + description: t('notifications.slack.description'), + fields: [ + { + id: 'webhook', + label: t('notifications.slack.webhookLabel'), + placeholder: t('notifications.slack.webhookPlaceholder'), + type: 'text' + } + ] + }, + { + id: 'discord', + label: t('notifications.discord.label'), + description: t('notifications.discord.description'), + fields: [ + { + id: 'webhook', + label: t('notifications.discord.webhookLabel'), + placeholder: t('notifications.discord.webhookPlaceholder'), + type: 'text' + } + ] + }, + { + id: 'telegram', + label: t('notifications.telegram.label'), + description: t('notifications.telegram.description'), + fields: [ + { + id: 'token', + label: t('notifications.telegram.tokenLabel'), + placeholder: t('notifications.telegram.tokenPlaceholder'), + type: 'text' + }, + { + id: 'chatId', + label: t('notifications.telegram.chatIdLabel'), + placeholder: t('notifications.telegram.chatIdPlaceholder'), + type: 'text' + } + ] + }, + { + id: 'webhook', + label: t('notifications.webhook.label'), + description: t('notifications.webhook.description'), + fields: [ + { + id: 'url', + label: t('notifications.webhook.urlLabel'), + placeholder: t('notifications.webhook.urlPlaceholder'), + type: 'text' + } + ] + } + ]; + + // Use provided notification types or default to our translated ones + const activeNotificationTypes = notificationTypes || DEFAULT_NOTIFICATION_TYPES; + // Memoized function to initialize integrations state const initialIntegrationsState = useMemo(() => { const state = {}; - notificationTypes.forEach(type => { + activeNotificationTypes.forEach(type => { // Add enabled flag for each notification type state[type.id] = monitor?.notifications?.some(n => n.type === type.id) || false; @@ -122,7 +107,7 @@ const NotificationIntegrationModal = ({ }); return state; - }, [monitor, notificationTypes]); // Only recompute when these dependencies change + }, [monitor, activeNotificationTypes]); // Only recompute when these dependencies change const [integrations, setIntegrations] = useState(initialIntegrationsState); @@ -154,7 +139,7 @@ const NotificationIntegrationModal = ({ const notifications = [...(monitor?.notifications || [])]; // Get all notification types IDs - const existingTypes = notificationTypes.map(type => type.id); + const existingTypes = activeNotificationTypes.map(type => type.id); // Filter out notifications that are configurable in this modal const filteredNotifications = notifications.filter( @@ -162,7 +147,7 @@ const NotificationIntegrationModal = ({ ); // Add each enabled notification with its configured fields - notificationTypes.forEach(type => { + activeNotificationTypes.forEach(type => { if (integrations[type.id]) { const notificationObject = { type: type.id @@ -220,7 +205,7 @@ const NotificationIntegrationModal = ({ color: theme.palette.primary.contrastTextSecondary, pl: theme.spacing(4) }}> - {t('notifications.addOrEditNotifications', 'Add or edit notifications')} + {t('notifications.addOrEditNotifications')} - {notificationTypes.map((type) => ( + {activeNotificationTypes.map((type) => ( @@ -247,19 +232,10 @@ const NotificationIntegrationModal = ({ pl: theme.spacing(7.5), overflowY: 'auto' }}> - {notificationTypes.map((type, index) => ( + {activeNotificationTypes.map((type, index) => ( ({ - ...field, - label: t(field.labelKey, field.label), - placeholder: t(field.placeholderKey, field.placeholder) - })) - }} + type={type} integrations={integrations} handleIntegrationChange={handleIntegrationChange} handleInputChange={handleInputChange} From 136452a6f5d3866710d19b9fde349d852e58d0ef Mon Sep 17 00:00:00 2001 From: Skorpios Date: Sun, 9 Mar 2025 20:26:06 -0700 Subject: [PATCH 20/20] Comment out notification integration button until fully functional. --- src/Pages/Uptime/Create/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Pages/Uptime/Create/index.jsx b/src/Pages/Uptime/Create/index.jsx index ebafa3a1f..3b295f586 100644 --- a/src/Pages/Uptime/Create/index.jsx +++ b/src/Pages/Uptime/Create/index.jsx @@ -413,7 +413,7 @@ const CreateMonitor = () => { onChange={(event) => handleNotifications(event, "email")} /> - + {/* - + */}