diff --git a/client/src/pages/Alerts.jsx b/client/src/pages/Alerts.jsx index d8654b8..7bb191c 100644 --- a/client/src/pages/Alerts.jsx +++ b/client/src/pages/Alerts.jsx @@ -462,7 +462,9 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => { device_ids: [], drone_types: [], min_rssi: '', - max_rssi: '' + max_rssi: '', + sms_phone_number: '', + webhook_url: '' }); const [saving, setSaving] = useState(false); const [devices, setDevices] = useState([]); @@ -502,6 +504,11 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => { if (!payload.max_rssi) delete payload.max_rssi; if (!payload.device_ids || payload.device_ids.length === 0) payload.device_ids = null; if (!payload.drone_types || payload.drone_types.length === 0) payload.drone_types = null; + + // Only include webhook_url if webhook channel is selected + if (!payload.alert_channels || !payload.alert_channels.includes('webhook')) { + delete payload.webhook_url; + } await api.post('/alerts/rules', payload); onSave(); @@ -733,6 +740,46 @@ const CreateAlertRuleModal = ({ onClose, onSave }) => { )} + + {/* Conditional channel-specific fields */} + {formData.alert_channels.includes('sms') && ( +
+ + +
+ Include country code (e.g., +1 for US) +
+
+ )} + + {formData.alert_channels.includes('webhook') && ( +
+ + +
+ Must be a valid HTTPS URL +
+
+ )} diff --git a/server/routes/alert.js b/server/routes/alert.js index 12e27a9..be5395a 100644 --- a/server/routes/alert.js +++ b/server/routes/alert.js @@ -18,7 +18,7 @@ const alertRuleSchema = Joi.object({ min_detections: Joi.number().integer().min(1).default(1), cooldown_period: Joi.number().integer().min(0).default(600), alert_channels: Joi.array().items(Joi.string().valid('sms', 'email', 'webhook')).default(['sms']), - webhook_url: Joi.string().uri().optional(), + webhook_url: Joi.string().uri().allow('').optional(), active_hours: Joi.object({ start: Joi.string().pattern(/^\d{2}:\d{2}$/).optional(), end: Joi.string().pattern(/^\d{2}:\d{2}$/).optional() @@ -66,6 +66,21 @@ router.get('/rules', authenticateToken, async (req, res) => { // POST /api/alerts/rules - Create new alert rule router.post('/rules', authenticateToken, validateRequest(alertRuleSchema), async (req, res) => { try { + // Custom validation for webhook URL when webhook channel is selected + if (req.body.alert_channels && req.body.alert_channels.includes('webhook')) { + if (!req.body.webhook_url || req.body.webhook_url.trim() === '') { + return res.status(400).json({ + success: false, + message: 'Validation error', + errors: [{ + field: 'webhook_url', + message: 'Webhook URL is required when webhook channel is selected', + value: req.body.webhook_url || '' + }] + }); + } + } + const alertRule = await AlertRule.create({ ...req.body, user_id: req.user.id