diff --git a/application/src/components/services/ResponseTimeChart.tsx b/application/src/components/services/ResponseTimeChart.tsx index ab046d8..51d04e2 100644 --- a/application/src/components/services/ResponseTimeChart.tsx +++ b/application/src/components/services/ResponseTimeChart.tsx @@ -184,7 +184,7 @@ export function ResponseTimeChart({ uptimeData }: ResponseTimeChartProps) { if (data?.agent_id && data.agent_id !== '1') { label = `${regionName} (${data.agent_id})`; } else if (regionName === 'Default' && data?.agent_id === '1') { - label = `Default (Agent 1)`; + label = `Default System Check (Agent 1)`; } const colorIndex = index % modernColors.length; diff --git a/application/src/components/services/ServiceForm.tsx b/application/src/components/services/ServiceForm.tsx index f9342f2..b353005 100644 --- a/application/src/components/services/ServiceForm.tsx +++ b/application/src/components/services/ServiceForm.tsx @@ -1,228 +1,3 @@ -import { Form } from "@/components/ui/form"; -import { useForm } from "react-hook-form"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useState, useEffect } from "react"; -import { useToast } from "@/hooks/use-toast"; -import { serviceSchema, ServiceFormData } from "./add-service/types"; -import { ServiceBasicFields } from "./add-service/ServiceBasicFields"; -import { ServiceTypeField } from "./add-service/ServiceTypeField"; -import { ServiceConfigFields } from "./add-service/ServiceConfigFields"; -import { ServiceNotificationFields } from "./add-service/ServiceNotificationFields"; -import { ServiceFormActions } from "./add-service/ServiceFormActions"; -import { serviceService } from "@/services/serviceService"; -import { Service } from "@/types/service.types"; -import { ServiceRegionalFields } from "./add-service/ServiceRegionalFields"; - -interface ServiceFormProps { - onSuccess: () => void; - onCancel: () => void; - initialData?: Service | null; - isEdit?: boolean; - onSubmitStart?: () => void; -} - -export function ServiceForm({ - onSuccess, - onCancel, - initialData, - isEdit = false, - onSubmitStart -}: ServiceFormProps) { - const { toast } = useToast(); - const [isSubmitting, setIsSubmitting] = useState(false); - - // Initialize form with default values - const form = useForm({ - resolver: zodResolver(serviceSchema), - defaultValues: { - name: "", - type: "http", - url: "", - port: "", - interval: "60", - retries: "3", - notificationChannel: "", - alertTemplate: "", - regionalMonitoringEnabled: false, - regionalAgent: "", - }, - mode: "onBlur", - }); - - // Populate form when initialData changes (separate from initialization) - useEffect(() => { - if (initialData && isEdit) { - // Ensure the type is one of the allowed values - const serviceType = (initialData.type || "http").toLowerCase(); - const validType = ["http", "ping", "tcp", "dns"].includes(serviceType) - ? serviceType as "http" | "ping" | "tcp" | "dns" - : "http"; - - // For PING services, use host field; for DNS use domain field; for TCP use host field; others use url - let urlValue = ""; - let portValue = ""; - - if (validType === "ping") { - urlValue = initialData.host || ""; - } else if (validType === "dns") { - urlValue = initialData.domain || ""; - } else if (validType === "tcp") { - urlValue = initialData.host || ""; - portValue = String(initialData.port || ""); - } else { - urlValue = initialData.url || ""; - } - - // Handle regional monitoring data - check regional_status field - const isRegionalEnabled = initialData.regional_status === "enabled"; - const regionalAgent = isRegionalEnabled && initialData.region_name && initialData.agent_id - ? `${initialData.region_name}|${initialData.agent_id}` - : ""; - - // Reset the form with initial data values - form.reset({ - name: initialData.name || "", - type: validType, - url: urlValue, - port: portValue, - interval: String(initialData.interval || 60), - retries: String(initialData.retries || 3), - notificationChannel: initialData.notificationChannel === "none" ? "" : initialData.notificationChannel || "", - alertTemplate: initialData.alertTemplate === "default" ? "" : initialData.alertTemplate || "", - regionalMonitoringEnabled: isRegionalEnabled, - regionalAgent: regionalAgent, - }); - - // Log for debugging - console.log("Populating form with data:", { - type: validType, - url: urlValue, - port: portValue, - regionalAgent, - regionalMonitoringEnabled: isRegionalEnabled, - regional_status: initialData.regional_status, - region_name: initialData.region_name, - agent_id: initialData.agent_id - }); - } - }, [initialData, isEdit, form]); - - const handleSubmit = async (data: ServiceFormData) => { - if (isSubmitting) return; - - setIsSubmitting(true); - if (onSubmitStart) onSubmitStart(); - - try { - console.log("Form data being submitted:", data); // Debug log for submitted data - - // Parse regional agent selection - let regionName = ""; - let agentId = ""; - let regionalStatus: "enabled" | "disabled" = "disabled"; - - // Set regional status and agent data based on form values - if (data.regionalMonitoringEnabled) { - regionalStatus = "enabled"; - if (data.regionalAgent && data.regionalAgent !== "") { - const [parsedRegionName, parsedAgentId] = data.regionalAgent.split("|"); - regionName = parsedRegionName || ""; - agentId = parsedAgentId || ""; - } - } - - // Prepare service data with proper field mapping - const serviceData = { - name: data.name, - type: data.type, - interval: parseInt(data.interval), - retries: parseInt(data.retries), - notificationChannel: data.notificationChannel === "none" ? "" : data.notificationChannel, - alertTemplate: data.alertTemplate === "default" ? "" : data.alertTemplate, - // Use regional_status field instead of regionalMonitoringEnabled - regionalStatus: regionalStatus, - regionName: regionName, - agentId: agentId, - // Map the URL field to appropriate database field based on service type - ...(data.type === "dns" - ? { domain: data.url, url: "", host: "", port: undefined } // DNS: store in domain field - : data.type === "ping" - ? { host: data.url, url: "", domain: "", port: undefined } // PING: store in host field - : data.type === "tcp" - ? { host: data.url, port: parseInt(data.port || "80"), url: "", domain: "" } // TCP: store in host and port fields - : { url: data.url, domain: "", host: "", port: undefined } // HTTP: store in url field - ) - }; - - console.log("Service data being sent:", serviceData); - - if (isEdit && initialData) { - // Update existing service - await serviceService.updateService(initialData.id, serviceData); - - toast({ - title: "Service updated", - description: `${data.name} has been updated successfully.`, - }); - } else { - // Create new service - await serviceService.createService(serviceData); - - toast({ - title: "Service created", - description: `${data.name} has been added to monitoring.`, - }); - } - - onSuccess(); - if (!isEdit) { - form.reset(); - } - } catch (error) { - console.error(`Error ${isEdit ? 'updating' : 'creating'} service:`, error); - toast({ - title: `Failed to ${isEdit ? 'update' : 'create'} service`, - description: `An error occurred while ${isEdit ? 'updating' : 'creating'} the service.`, - variant: "destructive", - }); - } finally { - setIsSubmitting(false); - } - }; - - return ( -
- -
-
-

Basic Information

- - -
- -
-

Configuration

- -
- -
-

Regional Monitoring

- -
- -
-

Notifications

- -
-
- - - - - ); -} \ No newline at end of file +// Re-export the ServiceForm component from the add-service directory +export { ServiceForm } from './add-service/ServiceForm'; \ No newline at end of file diff --git a/application/src/components/services/add-service/ServiceForm.tsx b/application/src/components/services/add-service/ServiceForm.tsx index b8b82c2..1fad41a 100644 --- a/application/src/components/services/add-service/ServiceForm.tsx +++ b/application/src/components/services/add-service/ServiceForm.tsx @@ -4,7 +4,6 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useState, useEffect } from "react"; import { useToast } from "@/hooks/use-toast"; -import { useQueryClient } from "@tanstack/react-query"; import { serviceSchema, ServiceFormData } from "./types"; import { ServiceBasicFields } from "./ServiceBasicFields"; import { ServiceTypeField } from "./ServiceTypeField"; @@ -14,6 +13,7 @@ import { ServiceFormActions } from "./ServiceFormActions"; import { serviceService } from "@/services/serviceService"; import { Service } from "@/types/service.types"; import { ServiceRegionalFields } from "./ServiceRegionalFields"; +import { getServiceFormDefaults, mapServiceToFormData, mapFormDataToServiceData } from "./serviceFormUtils"; interface ServiceFormProps { onSuccess: () => void; @@ -36,73 +36,28 @@ export function ServiceForm({ // Initialize form with default values const form = useForm({ resolver: zodResolver(serviceSchema), - defaultValues: { - name: "", - type: "http", - url: "", - port: "", - interval: "60", - retries: "3", - notificationChannel: "", - alertTemplate: "", - regionalMonitoringEnabled: false, - regionalAgent: "", - }, + defaultValues: getServiceFormDefaults(), mode: "onBlur", }); // Populate form when initialData changes (separate from initialization) useEffect(() => { if (initialData && isEdit) { - // Ensure the type is one of the allowed values - const serviceType = (initialData.type || "http").toLowerCase(); - const validType = ["http", "ping", "tcp", "dns"].includes(serviceType) - ? serviceType as "http" | "ping" | "tcp" | "dns" - : "http"; - - // For PING services, use host field; for DNS use domain field; for TCP use host field; others use url - let urlValue = ""; - let portValue = ""; - - if (validType === "ping") { - urlValue = initialData.host || ""; - } else if (validType === "dns") { - urlValue = initialData.domain || ""; - } else if (validType === "tcp") { - urlValue = initialData.host || ""; - portValue = String(initialData.port || ""); - } else { - urlValue = initialData.url || ""; - } - - // Handle regional monitoring data - ensure proper assignment display - const regionalAgent = initialData.region_name && initialData.agent_id - ? `${initialData.region_name}|${initialData.agent_id}` - : ""; - - // Reset the form with initial data values - form.reset({ - name: initialData.name || "", - type: validType, - url: urlValue, - port: portValue, - interval: String(initialData.interval || 60), - retries: String(initialData.retries || 3), - notificationChannel: initialData.notificationChannel || "", - alertTemplate: initialData.alertTemplate || "", - regionalMonitoringEnabled: Boolean(initialData.regional_monitoring_enabled), - regionalAgent: regionalAgent, - }); + const formData = mapServiceToFormData(initialData); + form.reset(formData); // Log for debugging console.log("Populating form with data:", { - type: validType, - url: urlValue, - port: portValue, - regionalAgent, - regionalMonitoringEnabled: Boolean(initialData.regional_monitoring_enabled), + type: formData.type, + url: formData.url, + port: formData.port, + regionalAgent: formData.regionalAgent, + regionalMonitoringEnabled: formData.regionalMonitoringEnabled, + regional_status: initialData.regional_status, region_name: initialData.region_name, - agent_id: initialData.agent_id + agent_id: initialData.agent_id, + notification_status: initialData.notification_status, + notificationChannels: formData.notificationChannels }); } }, [initialData, isEdit, form]); @@ -114,42 +69,9 @@ export function ServiceForm({ if (onSubmitStart) onSubmitStart(); try { - console.log("Form data being submitted:", data); // Debug log for submitted data + console.log("Form data being submitted:", data); - // Parse regional agent selection - let regionName = ""; - let agentId = ""; - - // Only set region and agent if regional monitoring is enabled AND an agent is selected (not unassign) - if (data.regionalMonitoringEnabled && data.regionalAgent && data.regionalAgent !== "") { - const [parsedRegionName, parsedAgentId] = data.regionalAgent.split("|"); - regionName = parsedRegionName || ""; - agentId = parsedAgentId || ""; - } - - // Prepare service data with proper field mapping - const serviceData = { - name: data.name, - type: data.type, - interval: parseInt(data.interval), - retries: parseInt(data.retries), - notificationChannel: data.notificationChannel || undefined, - alertTemplate: data.alertTemplate || undefined, - regionalMonitoringEnabled: data.regionalMonitoringEnabled || false, - // Always set region_name and agent_id - empty strings when unassigned - regionName: regionName, - agentId: agentId, - // Map the URL field to appropriate database field based on service type - ...(data.type === "dns" - ? { domain: data.url, url: "", host: "", port: undefined } // DNS: store in domain field - : data.type === "ping" - ? { host: data.url, url: "", domain: "", port: undefined } // PING: store in host field - : data.type === "tcp" - ? { host: data.url, port: parseInt(data.port || "80"), url: "", domain: "" } // TCP: store in host and port fields - : { url: data.url, domain: "", host: "", port: undefined } // HTTP: store in url field - ) - }; - + const serviceData = mapFormDataToServiceData(data); console.log("Service data being sent:", serviceData); if (isEdit && initialData) { @@ -188,7 +110,7 @@ export function ServiceForm({ return (
- +

Basic Information

diff --git a/application/src/components/services/add-service/ServiceNotificationFields.tsx b/application/src/components/services/add-service/ServiceNotificationFields.tsx index aae20d0..1d8441a 100644 --- a/application/src/components/services/add-service/ServiceNotificationFields.tsx +++ b/application/src/components/services/add-service/ServiceNotificationFields.tsx @@ -1,10 +1,12 @@ -import { FormControl, FormField, FormItem, FormLabel } from "@/components/ui/form"; +import { FormControl, FormField, FormItem, FormLabel, FormDescription } from "@/components/ui/form"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; +import { Badge } from "@/components/ui/badge"; +import { X } from "lucide-react"; import { UseFormReturn } from "react-hook-form"; import { ServiceFormData } from "./types"; import { useQuery } from "@tanstack/react-query"; -import { templateService } from "@/services/templateService"; import { alertConfigService, AlertConfiguration } from "@/services/alertConfigService"; import { useState, useEffect } from "react"; @@ -16,11 +18,13 @@ export function ServiceNotificationFields({ form }: ServiceNotificationFieldsPro const [alertConfigs, setAlertConfigs] = useState([]); // Get the current form values for debugging - const notificationChannel = form.watch("notificationChannel"); + const notificationStatus = form.watch("notificationStatus"); + const notificationChannels = form.watch("notificationChannels") || []; const alertTemplate = form.watch("alertTemplate"); console.log("Current notification values:", { - notificationChannel, + notificationStatus, + notificationChannels, alertTemplate }); @@ -30,12 +34,6 @@ export function ServiceNotificationFields({ form }: ServiceNotificationFieldsPro queryFn: () => alertConfigService.getAlertConfigurations(), }); - // Fetch templates for template selection - const { data: templates } = useQuery({ - queryKey: ['templates'], - queryFn: () => templateService.getTemplates(), - }); - // Update alert configs when data is loaded useEffect(() => { if (alertConfigsData) { @@ -51,53 +49,110 @@ export function ServiceNotificationFields({ form }: ServiceNotificationFieldsPro // Log when form values change to debug useEffect(() => { console.log("Notification values changed:", { - notificationChannel: form.getValues("notificationChannel"), - alertTemplate: form.getValues("alertTemplate") + notificationStatus: form.getValues("notificationStatus"), + notificationChannels: form.getValues("notificationChannels") }); - }, [form.watch("notificationChannel"), form.watch("alertTemplate")]); + }, [form.watch("notificationStatus"), form.watch("notificationChannels")]); + + const handleChannelAdd = (channelId: string) => { + const currentChannels = form.getValues("notificationChannels") || []; + if (!currentChannels.includes(channelId)) { + form.setValue("notificationChannels", [...currentChannels, channelId]); + } + }; + + const handleChannelRemove = (channelId: string) => { + const currentChannels = form.getValues("notificationChannels") || []; + form.setValue("notificationChannels", currentChannels.filter(id => id !== channelId)); + }; + + const getSelectedChannelNames = () => { + return (notificationChannels || []).map(channelId => { + const config = alertConfigs.find(c => c.id === channelId); + return config ? `${config.notify_name} (${config.notification_type})` : channelId; + }); + }; return ( <> { - // Important: We need to preserve the actual value for notification channel - const fieldValue = field.value || ""; - const displayValue = fieldValue === "" ? "none" : fieldValue; - - console.log("Rendering notification channel field with value:", { - fieldValue, - displayValue - }); - - return ( - - Notification Channel - - + + + + + {alertConfigs + .filter(config => !notificationChannels?.includes(config.id || "")) + .map((config) => ( {config.notify_name} ({config.notification_type}) ))} - - - - - ); - }} + + + + + )} /> - + Default - {templates?.map((template) => ( - - {template.name} - - ))} + {/* Add templates here when available */} + + {notificationStatus === "enabled" + ? "Choose a template for alert messages" + : "Enable notifications first to select template"} + ); }} /> ); -} \ No newline at end of file +} diff --git a/application/src/components/services/add-service/serviceFormUtils.ts b/application/src/components/services/add-service/serviceFormUtils.ts new file mode 100644 index 0000000..7d9171d --- /dev/null +++ b/application/src/components/services/add-service/serviceFormUtils.ts @@ -0,0 +1,122 @@ + +import { Service } from "@/types/service.types"; +import { ServiceFormData } from "./types"; + +export const getServiceFormDefaults = (): ServiceFormData => ({ + name: "", + type: "http", + url: "", + port: "", + interval: "60", + retries: "3", + notificationStatus: "disabled", + notificationChannels: [], + alertTemplate: "", + regionalMonitoringEnabled: false, + regionalAgent: "", +}); + +export const mapServiceToFormData = (service: Service): ServiceFormData => { + // Ensure the type is one of the allowed values + const serviceType = (service.type || "http").toLowerCase(); + const validType = ["http", "ping", "tcp", "dns"].includes(serviceType) + ? serviceType as "http" | "ping" | "tcp" | "dns" + : "http"; + + // For PING services, use host field; for DNS use domain field; for TCP use host field; others use url + let urlValue = ""; + let portValue = ""; + + if (validType === "ping") { + urlValue = service.host || ""; + } else if (validType === "dns") { + urlValue = service.domain || ""; + } else if (validType === "tcp") { + urlValue = service.host || ""; + portValue = String(service.port || ""); + } else { + urlValue = service.url || ""; + } + + // Handle regional monitoring data - check regional_status field + const isRegionalEnabled = service.regional_status === "enabled"; + const regionalAgent = isRegionalEnabled && service.region_name && service.agent_id + ? `${service.region_name}|${service.agent_id}` + : ""; + + // Handle notification channels - convert notification_channel and notificationChannel to array + const notificationChannels: string[] = []; + + // Check for notification_channel field (from database) + if (service.notification_channel) { + notificationChannels.push(service.notification_channel); + } + + // Also check for notificationChannel field (backward compatibility) + if (service.notificationChannel && !notificationChannels.includes(service.notificationChannel)) { + notificationChannels.push(service.notificationChannel); + } + + console.log("Mapping service to form data:", { + serviceName: service.name, + notification_status: service.notification_status, + notification_channel: service.notification_channel, + notificationChannel: service.notificationChannel, + mappedChannels: notificationChannels + }); + + return { + name: service.name || "", + type: validType, + url: urlValue, + port: portValue, + interval: String(service.interval || 60), + retries: String(service.retries || 3), + notificationStatus: service.notification_status || "disabled", + notificationChannels: notificationChannels, + alertTemplate: service.alertTemplate === "default" ? "" : service.alertTemplate || "", + regionalMonitoringEnabled: isRegionalEnabled, + regionalAgent: regionalAgent, + }; +}; + +export const mapFormDataToServiceData = (data: ServiceFormData) => { + // Parse regional agent selection + let regionName = ""; + let agentId = ""; + let regionalStatus: "enabled" | "disabled" = "disabled"; + + // Set regional status and agent data based on form values + if (data.regionalMonitoringEnabled) { + regionalStatus = "enabled"; + if (data.regionalAgent && data.regionalAgent !== "") { + const [parsedRegionName, parsedAgentId] = data.regionalAgent.split("|"); + regionName = parsedRegionName || ""; + agentId = parsedAgentId || ""; + } + } + + // Prepare service data with proper field mapping + return { + name: data.name, + type: data.type, + interval: parseInt(data.interval), + retries: parseInt(data.retries), + notificationStatus: data.notificationStatus || "disabled", + notificationChannels: data.notificationChannels || [], + alertTemplate: data.alertTemplate === "default" ? "" : data.alertTemplate, + // Use regional_status field instead of regionalMonitoringEnabled + regionalStatus: regionalStatus, + regionName: regionName, + agentId: agentId, + // Map the URL field to appropriate database field based on service type + ...(data.type === "dns" + ? { domain: data.url, url: "", host: "", port: undefined } // DNS: store in domain field + : data.type === "ping" + ? { host: data.url, url: "", domain: "", port: undefined } // PING: store in host field + : data.type === "tcp" + ? { host: data.url, port: parseInt(data.port || "80"), url: "", domain: "" } // TCP: store in host and port fields + : { url: data.url, domain: "", host: "", port: undefined } // HTTP: store in url field + ) + }; +}; \ No newline at end of file diff --git a/application/src/components/services/add-service/types.ts b/application/src/components/services/add-service/types.ts index c276e4d..3d269e5 100644 --- a/application/src/components/services/add-service/types.ts +++ b/application/src/components/services/add-service/types.ts @@ -11,11 +11,12 @@ export const serviceSchema = z.object({ port: z.string().optional(), interval: z.string(), retries: z.string(), - notificationChannel: z.string().optional(), + notificationStatus: z.enum(["enabled", "disabled"]).optional(), + notificationChannels: z.array(z.string()).optional(), alertTemplate: z.string().optional(), // Regional monitoring fields regionalMonitoringEnabled: z.boolean().optional(), regionalAgent: z.string().optional(), }); -export type ServiceFormData = z.infer; \ No newline at end of file +export type ServiceFormData = z.infer; diff --git a/application/src/components/services/hooks/useConsolidatedUptimeData.ts b/application/src/components/services/hooks/useConsolidatedUptimeData.ts index 5fb40f7..433f8b2 100644 --- a/application/src/components/services/hooks/useConsolidatedUptimeData.ts +++ b/application/src/components/services/hooks/useConsolidatedUptimeData.ts @@ -107,7 +107,7 @@ export const useConsolidatedUptimeData = ({ serviceId, serviceType, status, inte console.log(`Found default monitoring: ${sourceName} for normalized timestamp ${normalizedTimestamp}`); } else { // Default monitoring fallback - sourceName = 'Default (Agent 1)'; + sourceName = 'Default System Check (Agent 1)'; isDefault = true; console.log(`Using fallback default monitoring for normalized timestamp ${normalizedTimestamp}`); } diff --git a/application/src/components/services/index.ts b/application/src/components/services/index.ts index a1daa8c..d314f50 100644 --- a/application/src/components/services/index.ts +++ b/application/src/components/services/index.ts @@ -13,3 +13,4 @@ export * from './ServicesTableView'; export * from './ServiceDeleteDialog'; export * from './ServiceHistoryDialog'; export * from './ServiceEditDialog'; +export * from './ServiceForm'; \ No newline at end of file diff --git a/application/src/components/ui/badge.tsx b/application/src/components/ui/badge.tsx index f000e3e..8963a4d 100644 --- a/application/src/components/ui/badge.tsx +++ b/application/src/components/ui/badge.tsx @@ -1,3 +1,4 @@ + import * as React from "react" import { cva, type VariantProps } from "class-variance-authority" diff --git a/application/src/services/serviceService.ts b/application/src/services/serviceService.ts index 4a00345..cebc4af 100644 --- a/application/src/services/serviceService.ts +++ b/application/src/services/serviceService.ts @@ -1,4 +1,3 @@ - import { pb } from '@/lib/pocketbase'; import { Service, CreateServiceParams, UptimeData } from '@/types/service.types'; import { monitoringService } from './monitoring'; @@ -28,6 +27,7 @@ export const serviceService = { interval: item.heartbeat_interval || item.interval || 60, retries: item.max_retries || item.retries || 3, notificationChannel: item.notification_id, + notification_status: item.notification_status || "disabled", alertTemplate: item.template_id, muteAlerts: item.alerts === "muted", // Convert string to boolean for compatibility alerts: item.alerts || "unmuted", // Store actual database field @@ -44,7 +44,7 @@ export const serviceService = { } }, - async createService(params: CreateServiceParams): Promise { + async createService(params: any): Promise { try { // Convert service type to lowercase to avoid validation issues const serviceType = params.type.toLowerCase(); @@ -61,7 +61,10 @@ export const serviceService = { last_checked: new Date().toLocaleString(), heartbeat_interval: params.interval, max_retries: params.retries, - notification_id: params.notificationChannel, + notification_status: params.notificationStatus || "disabled", + notification_id: params.notificationChannels && params.notificationChannels.length > 0 + ? params.notificationChannels[0] // Store first channel for backward compatibility + : null, template_id: params.alertTemplate, // Regional monitoring fields - use regional_status regional_status: params.regionalStatus || "disabled", @@ -98,6 +101,7 @@ export const serviceService = { interval: record.heartbeat_interval || 60, retries: record.max_retries || 3, notificationChannel: record.notification_id, + notification_status: record.notification_status || "disabled", alertTemplate: record.template_id, regional_status: record.regional_status || "disabled", regional_monitoring_enabled: record.regional_status === "enabled", @@ -115,7 +119,7 @@ export const serviceService = { } }, - async updateService(id: string, params: CreateServiceParams): Promise { + async updateService(id: string, params: any): Promise { try { // Convert service type to lowercase to avoid validation issues const serviceType = params.type.toLowerCase(); @@ -128,7 +132,10 @@ export const serviceService = { service_type: serviceType, heartbeat_interval: params.interval, max_retries: params.retries, - notification_id: params.notificationChannel || null, + notification_status: params.notificationStatus || "disabled", + notification_id: params.notificationChannels && params.notificationChannels.length > 0 + ? params.notificationChannels[0] // Store first channel for backward compatibility + : null, template_id: params.alertTemplate || null, // Regional monitoring fields - use regional_status regional_status: params.regionalStatus || "disabled", @@ -172,6 +179,7 @@ export const serviceService = { interval: record.heartbeat_interval || 60, retries: record.max_retries || 3, notificationChannel: record.notification_id, + notification_status: record.notification_status || "disabled", alertTemplate: record.template_id, regional_status: record.regional_status || "disabled", regional_monitoring_enabled: record.regional_status === "enabled", diff --git a/application/src/types/service.types.ts b/application/src/types/service.types.ts index 2653ea4..5071174 100644 --- a/application/src/types/service.types.ts +++ b/application/src/types/service.types.ts @@ -17,6 +17,7 @@ export interface Service { updated?: string; notification_channel?: string; notificationChannel?: string; // Keep for backward compatibility + notification_status?: "enabled" | "disabled"; // Add notification_status field alertTemplate?: string; alerts?: "muted" | "unmuted"; // Make sure alerts is properly typed as union muteAlerts?: boolean; // Keep this to avoid breaking existing code