From ddeb22dc4d3aabcbd579d346c6e7224900737fca Mon Sep 17 00:00:00 2001 From: Tola Leng Date: Wed, 9 Jul 2025 21:59:22 +0700 Subject: [PATCH 1/3] Added uptime monitoring detail data and server monitoring schema --- .../1750241370_updated_ping_data.js | 61 +++++++ .../1750241407_updated_regional_service.js | 42 +++++ .../1750414552_deleted_server_processes.js | 137 ++++++++++++++ ...1750414561_deleted_server_notifications.js | 170 ++++++++++++++++++ .../1750502263_updated_regional_service.js | 28 +++ 5 files changed, 438 insertions(+) create mode 100644 server/pb_migrations/1750241370_updated_ping_data.js create mode 100644 server/pb_migrations/1750241407_updated_regional_service.js create mode 100644 server/pb_migrations/1750414552_deleted_server_processes.js create mode 100644 server/pb_migrations/1750414561_deleted_server_notifications.js create mode 100644 server/pb_migrations/1750502263_updated_regional_service.js diff --git a/server/pb_migrations/1750241370_updated_ping_data.js b/server/pb_migrations/1750241370_updated_ping_data.js new file mode 100644 index 0000000..f197b25 --- /dev/null +++ b/server/pb_migrations/1750241370_updated_ping_data.js @@ -0,0 +1,61 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_1168766540") + + // remove field + collection.fields.removeById("text1404634243") + + // update field + collection.fields.addAt(15, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text258142582", + "max": 0, + "min": 0, + "name": "region_name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_1168766540") + + // add field + collection.fields.addAt(17, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1404634243", + "max": 0, + "min": 0, + "name": "agent_ip_address", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // update field + collection.fields.addAt(15, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text258142582", + "max": 0, + "min": 0, + "name": "region", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/server/pb_migrations/1750241407_updated_regional_service.js b/server/pb_migrations/1750241407_updated_regional_service.js new file mode 100644 index 0000000..84a577c --- /dev/null +++ b/server/pb_migrations/1750241407_updated_regional_service.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_171698555") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text258142582", + "max": 0, + "min": 0, + "name": "region_name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_171698555") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text258142582", + "max": 0, + "min": 0, + "name": "region", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/server/pb_migrations/1750414552_deleted_server_processes.js b/server/pb_migrations/1750414552_deleted_server_processes.js new file mode 100644 index 0000000..034c38d --- /dev/null +++ b/server/pb_migrations/1750414552_deleted_server_processes.js @@ -0,0 +1,137 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_2018671343"); + + return app.delete(collection); +}, (app) => { + const collection = new Collection({ + "createRule": "", + "deleteRule": "", + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text407168695", + "max": 0, + "min": 0, + "name": "server_id", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1431356653", + "max": 0, + "min": 0, + "name": "pid", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 0, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "number1391558374", + "max": null, + "min": null, + "name": "memory_percent", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "hidden": false, + "id": "number2651913466", + "max": null, + "min": null, + "name": "cpu_percent", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text2063623452", + "max": 0, + "min": 0, + "name": "status", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_2018671343", + "indexes": [], + "listRule": "", + "name": "server_processes", + "system": false, + "type": "base", + "updateRule": "", + "viewRule": "" + }); + + return app.save(collection); +}) diff --git a/server/pb_migrations/1750414561_deleted_server_notifications.js b/server/pb_migrations/1750414561_deleted_server_notifications.js new file mode 100644 index 0000000..4a4b0aa --- /dev/null +++ b/server/pb_migrations/1750414561_deleted_server_notifications.js @@ -0,0 +1,170 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3414192583"); + + return app.delete(collection); +}, (app) => { + const collection = new Collection({ + "createRule": "", + "deleteRule": "", + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text407168695", + "max": 0, + "min": 0, + "name": "server_id", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3065852031", + "max": 0, + "min": 0, + "name": "message", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text887233555", + "max": 0, + "min": 0, + "name": "notification_type", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "date3805952114", + "max": "", + "min": "", + "name": "read_at", + "presentable": false, + "required": false, + "system": false, + "type": "date" + }, + { + "hidden": false, + "id": "number1377725610", + "max": null, + "min": null, + "name": "cpu_threshold", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "hidden": false, + "id": "number3087505384", + "max": null, + "min": null, + "name": "ram_threshold", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "hidden": false, + "id": "number2833320134", + "max": null, + "min": null, + "name": "disk_threshold", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "hidden": false, + "id": "number1826572927", + "max": null, + "min": null, + "name": "network_threshold", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "hidden": false, + "id": "number2184331740", + "max": null, + "min": null, + "name": "notification_config_id", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_3414192583", + "indexes": [], + "listRule": "", + "name": "server_notifications", + "system": false, + "type": "base", + "updateRule": "", + "viewRule": "" + }); + + return app.save(collection); +}) diff --git a/server/pb_migrations/1750502263_updated_regional_service.js b/server/pb_migrations/1750502263_updated_regional_service.js new file mode 100644 index 0000000..230a6ea --- /dev/null +++ b/server/pb_migrations/1750502263_updated_regional_service.js @@ -0,0 +1,28 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_171698555") + + // update collection data + unmarshal({ + "createRule": "", + "deleteRule": "", + "listRule": "", + "updateRule": "", + "viewRule": "" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_171698555") + + // update collection data + unmarshal({ + "createRule": null, + "deleteRule": null, + "listRule": null, + "updateRule": null, + "viewRule": null + }, collection) + + return app.save(collection) +}) From 917d8a6d2909c6c56056b3c0ae3ac456dc8e7756 Mon Sep 17 00:00:00 2001 From: Tola Leng Date: Thu, 10 Jul 2025 21:07:31 +0700 Subject: [PATCH 2/3] feat: Implement notification channel based on status (Service Dialog Form and Refactor Split ServiceForm into smaller components). - The Service Dialog Form's Notification Channel field now respects the `notification_status`. If `notification_status` is enabled, the user can select one or multiple notification channel IDs. --- .../components/services/ResponseTimeChart.tsx | 2 +- .../src/components/services/ServiceForm.tsx | 229 +----------------- .../services/add-service/ServiceForm.tsx | 110 ++------- .../add-service/ServiceNotificationFields.tsx | 165 ++++++++----- .../services/add-service/serviceFormUtils.ts | 122 ++++++++++ .../components/services/add-service/types.ts | 5 +- .../hooks/useConsolidatedUptimeData.ts | 2 +- application/src/components/services/index.ts | 1 + application/src/components/ui/badge.tsx | 1 + application/src/services/serviceService.ts | 18 +- application/src/types/service.types.ts | 1 + 11 files changed, 272 insertions(+), 384 deletions(-) create mode 100644 application/src/components/services/add-service/serviceFormUtils.ts 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 - - // Parse regional agent selection - let regionName = ""; - let agentId = ""; + console.log("Form data being submitted:", data); - // 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 From 2d2bd790b0ba022262bac2bb00f3556985902cbc Mon Sep 17 00:00:00 2001 From: Tola Leng Date: Thu, 10 Jul 2025 22:14:17 +0700 Subject: [PATCH 3/3] Disable the debug console logs for production --- application/src/api/index.ts | 10 +-- application/src/api/settings/index.ts | 4 +- .../src/components/dashboard/Header.tsx | 4 +- .../ScheduleIncidentContent.tsx | 8 +-- .../hooks/useIncidentData.ts | 20 +++--- .../MaintenanceNotificationSettingsField.tsx | 40 ++++++------ .../form/config/AssignedUsersField.tsx | 20 +++--- .../hooks/useRealTimeUpdates.tsx | 12 ++-- .../hooks/useServiceData.tsx | 36 +++++------ .../services/ServiceMonitoringButton.tsx | 8 +-- .../src/components/services/UptimeBar.tsx | 6 +- .../hooks/useConsolidatedUptimeData.ts | 64 +++++++++---------- .../services/hooks/useServiceActions.ts | 8 +-- .../incident-history/LatestChecksTable.tsx | 6 +- .../services/incident-history/utils.tsx | 2 +- .../alerts-templates/TemplateDialog.tsx | 4 +- .../ssl-domain/AddSSLCertificateForm.tsx | 6 +- .../ssl-domain/EditSSLCertificateForm.tsx | 4 +- .../ssl-domain/SSLDomainContent.tsx | 24 +++---- application/src/hooks/useSystemSettings.tsx | 16 ++--- application/src/pages/Dashboard.tsx | 4 +- application/src/pages/SslDomain.tsx | 8 +-- .../src/services/alertConfigService.ts | 24 +++---- application/src/services/authService.ts | 14 ++-- .../src/services/incident/incidentCache.ts | 4 +- .../src/services/incident/incidentFetch.ts | 20 +++--- .../maintenanceNotificationService.ts | 30 ++++----- .../service-status/startAllServices.ts | 4 +- .../service-status/startMonitoring.ts | 14 ++-- application/src/services/serviceService.ts | 2 +- .../src/services/ssl/sslFetchService.ts | 14 ++-- application/src/services/uptimeService.ts | 40 ++++++------ application/src/services/userService.ts | 60 ++++++++--------- 33 files changed, 270 insertions(+), 270 deletions(-) diff --git a/application/src/api/index.ts b/application/src/api/index.ts index c4f7f62..1fa86b7 100644 --- a/application/src/api/index.ts +++ b/application/src/api/index.ts @@ -11,19 +11,19 @@ const api = { * Handle API requests */ async handleRequest(path, method, body) { - console.log(`API request: ${method} ${path}`, body); + // console.log(`API request: ${method} ${path}`, body); // Route to the appropriate handler if (path === '/api/realtime') { - console.log("Routing to realtime handler"); + // console.log("Routing to realtime handler"); return await realtime(body); } else if (path === '/api/settings' || path.startsWith('/api/settings/')) { - console.log("Routing to settings handler"); + // console.log("Routing to settings handler"); return await settingsApi(body, path); } // Return 404 for unknown routes - console.error(`Endpoint not found: ${path}`); + // console.error(`Endpoint not found: ${path}`); return { status: 404, json: { @@ -40,7 +40,7 @@ const originalFetch = window.fetch; window.fetch = async (url, options = {}) => { // Check if this is an API request to our mock endpoints if (typeof url === 'string' && url.startsWith('/api/')) { - console.log('Intercepting API request:', url, options); + // console.log('Intercepting API request:', url, options); try { let body = {}; diff --git a/application/src/api/settings/index.ts b/application/src/api/settings/index.ts index 1be26bc..50d2b7d 100644 --- a/application/src/api/settings/index.ts +++ b/application/src/api/settings/index.ts @@ -8,7 +8,7 @@ import { testEmail } from './actions/testEmail'; * Settings API handler */ const settingsApi = async (body: any, path?: string) => { - console.log('Settings API called with path:', path, 'body:', body); + // console.log('Settings API called with path:', path, 'body:', body); // Handle test email endpoint specifically if (path === '/api/settings/test/email') { @@ -18,7 +18,7 @@ const settingsApi = async (body: any, path?: string) => { // Handle regular settings API with action-based routing const action = body?.action; - console.log('Settings API called with action:', action, 'data:', body?.data); + // console.log('Settings API called with action:', action, 'data:', body?.data); switch (action) { case 'getSettings': diff --git a/application/src/components/dashboard/Header.tsx b/application/src/components/dashboard/Header.tsx index bc98045..0e0815d 100644 --- a/application/src/components/dashboard/Header.tsx +++ b/application/src/components/dashboard/Header.tsx @@ -53,7 +53,7 @@ export const Header = ({ // Log avatar data for debugging useEffect(() => { if (currentUser) { - console.log("Avatar URL in Header:", currentUser.avatar); + // console.log("Avatar URL in Header:", currentUser.avatar); } }, [currentUser]); @@ -66,7 +66,7 @@ export const Header = ({ } else { avatarUrl = currentUser.avatar; } - console.log("Final avatar URL:", avatarUrl); + // console.log("Final avatar URL:", avatarUrl); } return ( diff --git a/application/src/components/schedule-incident/ScheduleIncidentContent.tsx b/application/src/components/schedule-incident/ScheduleIncidentContent.tsx index a3b8422..05ee42a 100644 --- a/application/src/components/schedule-incident/ScheduleIncidentContent.tsx +++ b/application/src/components/schedule-incident/ScheduleIncidentContent.tsx @@ -22,12 +22,12 @@ export const ScheduleIncidentContent = () => { // Initialize maintenance notifications when the component mounts useEffect(() => { - console.log("Initializing maintenance notifications"); + // console.log("Initializing maintenance notifications"); initMaintenanceNotifications(); // Clean up when the component unmounts return () => { - console.log("Cleaning up maintenance notifications"); + // console.log("Cleaning up maintenance notifications"); stopMaintenanceNotifications(); }; }, []); @@ -43,7 +43,7 @@ export const ScheduleIncidentContent = () => { const handleMaintenanceCreated = () => { // Refresh data by incrementing the refresh trigger const newTriggerValue = refreshTrigger + 1; - console.log("Maintenance created, refreshing data with new trigger value:", newTriggerValue); + // console.log("Maintenance created, refreshing data with new trigger value:", newTriggerValue); setRefreshTrigger(newTriggerValue); // Show success toast @@ -56,7 +56,7 @@ export const ScheduleIncidentContent = () => { const handleIncidentCreated = () => { // Refresh data by incrementing the refresh trigger const newTriggerValue = incidentRefreshTrigger + 1; - console.log("Incident created, refreshing data with new trigger value:", newTriggerValue); + // console.log("Incident created, refreshing data with new trigger value:", newTriggerValue); setIncidentRefreshTrigger(newTriggerValue); // Show success toast diff --git a/application/src/components/schedule-incident/hooks/useIncidentData.ts b/application/src/components/schedule-incident/hooks/useIncidentData.ts index d6b32cb..2e0a998 100644 --- a/application/src/components/schedule-incident/hooks/useIncidentData.ts +++ b/application/src/components/schedule-incident/hooks/useIncidentData.ts @@ -22,13 +22,13 @@ export const useIncidentData = ({ refreshTrigger = 0 }: UseIncidentDataProps) => const fetchIncidentData = useCallback(async (force = false) => { // Skip if already fetching if (isFetchingRef.current) { - console.log('Already fetching data, skipping additional request'); + // console.log('Already fetching data, skipping additional request'); return; } // Skip if not forced and already initialized if (initialized && !force) { - console.log('Data already initialized and no force refresh, skipping fetch'); + // console.log('Data already initialized and no force refresh, skipping fetch'); return; } @@ -46,22 +46,22 @@ export const useIncidentData = ({ refreshTrigger = 0 }: UseIncidentDataProps) => setError(null); try { - console.log(`Fetching incident data (force=${force})`); + // console.log(`Fetching incident data (force=${force})`); const allIncidents = await incidentService.getAllIncidents(force); if (Array.isArray(allIncidents)) { setIncidents(allIncidents); - console.log(`Successfully set ${allIncidents.length} incidents to state`); + // console.log(`Successfully set ${allIncidents.length} incidents to state`); } else { setIncidents([]); - console.warn('No incidents returned from service'); + // console.warn('No incidents returned from service'); } setInitialized(true); setLoading(false); setIsRefreshing(false); } catch (error) { - console.error('Error fetching incident data:', error); + // console.error('Error fetching incident data:', error); setError('Failed to load incident data. Please try again later.'); setIncidents([]); setInitialized(true); @@ -79,7 +79,7 @@ export const useIncidentData = ({ refreshTrigger = 0 }: UseIncidentDataProps) => useEffect(() => { // Skip if the refresh trigger hasn't changed (prevents duplicate effect calls) if (refreshTrigger === lastRefreshTriggerRef.current && initialized) { - console.log('Refresh trigger unchanged, skipping fetch'); + // console.log('Refresh trigger unchanged, skipping fetch'); return; } @@ -90,7 +90,7 @@ export const useIncidentData = ({ refreshTrigger = 0 }: UseIncidentDataProps) => const abortController = new AbortController(); let isMounted = true; - console.log(`useIncidentData effect running, refreshTrigger: ${refreshTrigger}`); + // console.log(`useIncidentData effect running, refreshTrigger: ${refreshTrigger}`); // Use a longer delay to ensure we don't trigger too many API calls const fetchTimer = setTimeout(() => { @@ -101,7 +101,7 @@ export const useIncidentData = ({ refreshTrigger = 0 }: UseIncidentDataProps) => // Cleanup function to abort any in-flight requests and clear timers return () => { - console.log('Cleaning up incident data fetch effect'); + // console.log('Cleaning up incident data fetch effect'); isMounted = false; clearTimeout(fetchTimer); abortController.abort(); @@ -112,7 +112,7 @@ export const useIncidentData = ({ refreshTrigger = 0 }: UseIncidentDataProps) => const incidentData = useMemo(() => { if (!initialized || incidents.length === 0) return []; - console.log(`Filtering incidents by: ${filter}`); + // console.log(`Filtering incidents by: ${filter}`); if (filter === "unresolved") { return incidents.filter(item => { diff --git a/application/src/components/schedule-incident/maintenance/form/MaintenanceNotificationSettingsField.tsx b/application/src/components/schedule-incident/maintenance/form/MaintenanceNotificationSettingsField.tsx index 65174a6..9ec629a 100644 --- a/application/src/components/schedule-incident/maintenance/form/MaintenanceNotificationSettingsField.tsx +++ b/application/src/components/schedule-incident/maintenance/form/MaintenanceNotificationSettingsField.tsx @@ -27,7 +27,7 @@ export const MaintenanceNotificationSettingsField = () => { try { setIsLoading(true); const channels = await alertConfigService.getAlertConfigurations(); - console.log("Fetched notification channels for form:", channels); + // console.log("Fetched notification channels for form:", channels); // Only show enabled channels const enabledChannels = channels.filter(channel => channel.enabled); @@ -38,18 +38,18 @@ export const MaintenanceNotificationSettingsField = () => { const currentChannel = getValues('notification_channel_id'); const shouldNotify = getValues('notify_subscribers'); - console.log("Current notification values:", { - currentChannel, - shouldNotify, - availableChannels: enabledChannels.length - }); + // console.log("Current notification values:", { + // currentChannel, + // shouldNotify, + // availableChannels: enabledChannels.length + // }); if (shouldNotify && (!currentChannel || currentChannel === 'none') && enabledChannels.length > 0) { - console.log("Setting default notification channel:", enabledChannels[0].id); + // console.log("Setting default notification channel:", enabledChannels[0].id); setValue('notification_channel_id', enabledChannels[0].id); } } catch (error) { - console.error('Error fetching notification channels:', error); + // console.error('Error fetching notification channels:', error); toast({ title: t('error'), description: t('errorFetchingNotificationChannels'), @@ -64,12 +64,12 @@ export const MaintenanceNotificationSettingsField = () => { }, [t, toast, setValue, getValues]); // Log value changes for debugging - useEffect(() => { - console.log("Current notification settings:", { - channel_id: getValues('notification_channel_id'), - notify: notifySubscribers - }); - }, [notifySubscribers, notificationChannelId, getValues]); + // useEffect(() => { + // console.log("Current notification settings:", { + // channel_id: getValues('notification_channel_id'), + // notify: notifySubscribers + // }); + // }, [notifySubscribers, notificationChannelId, getValues]); return (
@@ -98,7 +98,7 @@ export const MaintenanceNotificationSettingsField = () => { checked={field.value} onCheckedChange={(checked) => { field.onChange(checked); - console.log("Notification toggle changed to:", checked); + // console.log("Notification toggle changed to:", checked); // If notifications are disabled, also clear the notification channel if (!checked) { setValue('notification_channel_id', ''); @@ -120,10 +120,10 @@ export const MaintenanceNotificationSettingsField = () => { // Make sure to handle both empty string and "none" as special cases const displayValue = field.value || ""; - console.log("Rendering notification channel field with value:", { - fieldValue: field.value, - displayValue - }); + // console.log("Rendering notification channel field with value:", { + // fieldValue: field.value, + // displayValue + // }); return ( @@ -135,7 +135,7 @@ export const MaintenanceNotificationSettingsField = () => {