Repository: bluewave-labs/Checkmate
Pull request #1933: Implement edit functionality for infrastructure monitors
Author: login: vishnusn77
Created: 2025-03-15T07:12:07Z | Merged: 2025-03-19T20:08:10Z

## Describe your changes
- Added ability to edit settings for existing infrastructure monitors
- When clicked on configure, monitor data is fetched for the existing monitor and settings fields are populated
- Users can modify the settings values and save the changes
- Added validation for threshold values in the backend (creating seperate PR)
## Issue number
#1277 

Mention the issue number(s) this PR addresses (e.g., #123).

## Please ensure all items are checked off before requesting a review. "Checked off" means you need to add an "x" character between brackets so they turn into checkmarks.

- [x] (Do not skip this or your PR will be closed) I deployed the application locally.
- [x] (Do not skip this or your PR will be closed) I have performed a self-review and testing of my code.
- [x] I have included the issue # in the PR.
- [x] I have added i18n support to visible strings (instead of `<div>Add</div>`, use): 
```Javascript
const { t } = useTranslation();
<div>{t('add')}</div>
```
- [x] The issue I am working on is assigned to me.
- [x] I didn't use any hardcoded values (otherwise it will not scale, and will make it difficult to maintain consistency across the application).
- [x] I made sure font sizes, color choices etc are all referenced from the theme. I have no hardcoded dimensions.
- [x] My PR is granular and targeted to one specific feature.
- [x] I took a screenshot or a video and attached to this PR if there is a UI change.


https://github.com/user-attachments/assets/142a62e4-7a41-4570-97b9-9c658170df2a






Diff:
diff --git a/src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js b/src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js
index af453a7ee2..62bdf48111 100644
--- a/src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js
+++ b/src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js
@@ -96,19 +96,20 @@ export const getInfrastructureMonitorsByTeamId = createAsyncThunk(
 
 export const updateInfrastructureMonitor = createAsyncThunk(
 	"infrastructureMonitors/updateMonitor",
-	async (data, thunkApi) => {
+	async ({ monitorId, monitor }, thunkApi) => {
 		try {
-			const { monitor } = data;
 			const updatedFields = {
 				name: monitor.name,
 				description: monitor.description,
 				interval: monitor.interval,
 				notifications: monitor.notifications,
-				threshold: monitor.threshold,
+				thresholds: monitor.thresholds,
+				secret: monitor.secret,
 			};
 			const res = await networkService.updateMonitor({
-				monitorId: monitor._id,
-				updatedFields: updatedFields,
+				monitorId,
+				monitor,
+				updatedFields,
 			});
 			return res.data;
 		} catch (error) {
diff --git a/src/Pages/Infrastructure/Create/index.jsx b/src/Pages/Infrastructure/Create/index.jsx
index 2c2a5505ff..144f499fdb 100644
--- a/src/Pages/Infrastructure/Create/index.jsx
+++ b/src/Pages/Infrastructure/Create/index.jsx
@@ -1,12 +1,13 @@
 // React, Redux, Router
 import { useTheme } from "@emotion/react";
-import { useNavigate } from "react-router-dom";
-import { useState } from "react";
+import { useNavigate, useParams } from "react-router-dom";
+import { useState, useEffect } from "react";
 import { useSelector, useDispatch } from "react-redux";
 
 // Utility and Network
 import { infrastructureMonitorValidation } from "../../../Validation/validation";
-import { createInfrastructureMonitor } from "../../../Features/InfrastructureMonitors/infrastructureMonitorsSlice";
+import { createInfrastructureMonitor, updateInfrastructureMonitor } from "../../../Features/InfrastructureMonitors/infrastructureMonitorsSlice";
+import { useHardwareMonitorsFetch } from "../Details/Hooks/useHardwareMonitorsFetch";
 import { capitalizeFirstLetter } from "../../../Utils/stringUtils";
 import { useTranslation } from "react-i18next";
 
@@ -53,7 +54,14 @@ const CreateInfrastructureMonitor = () => {
 	const monitorState = useSelector((state) => state.infrastructureMonitor);
 	const dispatch = useDispatch();
 	const navigate = useNavigate();
-	const { t } = useTranslation();
+	const { monitorId } = useParams();
+	const { t } = useTranslation();	
+
+	// Determine if we are creating or editing
+	const isCreate = typeof monitorId === "undefined";
+
+	// Fetch monitor details if editing
+	const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId });
 
 	// State
 	const [errors, setErrors] = useState({});
@@ -62,6 +70,7 @@ const CreateInfrastructureMonitor = () => {
 		url: "",
 		name: "",
 		notifications: [],
+		notify_email: false,
 		interval: 0.25,
 		cpu: false,
 		usage_cpu: "",
@@ -74,10 +83,44 @@ const CreateInfrastructureMonitor = () => {
 		secret: "",
 	});
 
+	// Populate form fields if editing
+	useEffect(() => {
+		if (isCreate || !monitor) return;
+
+		setInfrastructureMonitor({
+			url: monitor.url.replace(/^https?:\/\//, ""),
+			name: monitor.name || "",
+			notifications: monitor.notifications?.filter(n => typeof n === "object") || [],
+			notify_email: (monitor.notifications?.length ?? 0) > 0,
+			interval: monitor.interval / MS_PER_MINUTE,
+			cpu: monitor.thresholds?.usage_cpu !== undefined,
+			usage_cpu: monitor.thresholds?.usage_cpu ? monitor.thresholds.usage_cpu * 100 : "",
+		
+			memory: monitor.thresholds?.usage_memory !== undefined,
+			usage_memory: monitor.thresholds?.usage_memory ? monitor.thresholds.usage_memory * 100 : "",
+		
+			disk: monitor.thresholds?.usage_disk !== undefined,
+			usage_disk: monitor.thresholds?.usage_disk ? monitor.thresholds.usage_disk * 100 : "",
+		
+			temperature: monitor.thresholds?.usage_temperature !== undefined,
+			usage_temperature: monitor.thresholds?.usage_temperature ? monitor.thresholds.usage_temperature * 100 : "",
+			secret: monitor.secret || "",
+		});
+		setHttps(monitor.url.startsWith("https"));
+	}, [isCreate, monitor]);
+
 	// Handlers
 	const handleCreateInfrastructureMonitor = async (event) => {
 		event.preventDefault();
 
+		const formattedNotifications = infrastructureMonitor.notifications.map((n) =>
+			typeof n === "string" ? { type: "email", address: n } : n
+		);
+
+		if (infrastructureMonitor.notify_email) {
+			formattedNotifications.push({ type: "email", address: user.email });
+		}
+
 		// Build the form
 		let form = {
 			url: `http${https ? "s" : ""}://` + infrastructureMonitor.url,
@@ -103,6 +146,7 @@ const CreateInfrastructureMonitor = () => {
 				? { usage_temperature: infrastructureMonitor.usage_temperature }
 				: {}),
 			secret: infrastructureMonitor.secret,
+			notifications: formattedNotifications,
 		};
 
 		const { error } = infrastructureMonitorValidation.validate(form, {
@@ -149,12 +193,17 @@ const CreateInfrastructureMonitor = () => {
 			thresholds,
 		};
 
-		const action = await dispatch(createInfrastructureMonitor({ monitor: form }));
+		// Handle create or update
+		const action = isCreate
+			? await dispatch(createInfrastructureMonitor({ monitor: form }))
+			: await dispatch(updateInfrastructureMonitor({ monitorId, monitor: form }));
 		if (action.meta.requestStatus === "fulfilled") {
-			createToast({ body: "Infrastructure monitor created successfully!" });
+			createToast({
+				body: isCreate ? t("infrastructureMonitorCreated") : t("infrastructureMonitorUpdated"),
+			});
 			navigate("/infrastructure");
 		} else {
-			createToast({ body: "Failed to create monitor." });
+			createToast({ body: "Failed to save monitor." });
 		}
 	};
 
@@ -185,37 +234,34 @@ const CreateInfrastructureMonitor = () => {
 	};
 
 	const handleNotifications = (event, type) => {
-		const { value } = event.target;
+		const { value, checked } = event.target;
 		let notifications = [...infrastructureMonitor.notifications];
-		const notificationExists = notifications.some((notification) => {
-			if (notification.type === type && notification.address === value) {
-				return true;
+	
+		if (checked) {
+			if (!notifications.some((n) => n.type === type && n.address === value)) {
+				notifications.push({ type, address: value });
 			}
-			return false;
-		});
-		if (notificationExists) {
-			notifications = notifications.filter((notification) => {
-				if (notification.type === type && notification.address === value) {
-					return false;
-				}
-				return true;
-			});
 		} else {
-			notifications.push({ type, address: value });
+			notifications = notifications.filter((n) => !(n.type === type && n.address === value));
 		}
-
+	
 		setInfrastructureMonitor((prev) => ({
 			...prev,
 			notifications,
+			...(type === "email" ? { notify_email: checked } : {})
 		}));
 	};
+	
 
 	return (
 		<Box className="create-infrastructure-monitor">
 			<Breadcrumbs
 				list={[
 					{ name: "Infrastructure monitors", path: "/infrastructure" },
-					{ name: "create", path: `/infrastructure/create` },
+					...(isCreate
+						? [{ name: "Create", path: "/infrastructure/create" }]
+						: [{ name: "Details", path: `/infrastructure/${monitorId}` }, { name: "Configure", path: `/infrastructure/configure/${monitorId}` }]
+					),
 				]}
 			/>
 			<Stack
@@ -235,7 +281,7 @@ const CreateInfrastructureMonitor = () => {
 						component="span"
 						fontSize="inherit"
 					>
-						{t("infrastructureCreateYour")}{" "}
+						{t(isCreate? "infrastructureCreateYour": "infrastructureEditYour")}{" "}
 					</Typography>
 					<Typography
 						component="span"
@@ -274,7 +320,9 @@ const CreateInfrastructureMonitor = () => {
 							onChange={handleChange}
 							error={errors["url"] ? true : false}
 							helperText={errors["url"]}
+							disabled={!isCreate}
 						/>
+						{isCreate && (
 						<Box>
 							<Typography component="p">{t("infrastructureProtocol")}</Typography>
 							<ButtonGroup>
@@ -294,6 +342,7 @@ const CreateInfrastructureMonitor = () => {
 								</Button>
 							</ButtonGroup>
 						</Box>
+						)}
 						<TextInput
 							type="text"
 							id="name"
@@ -328,9 +377,7 @@ const CreateInfrastructureMonitor = () => {
 						<Checkbox
 							id="notify-email-default"
 							label={`Notify via email (to ${user.email})`}
-							isChecked={infrastructureMonitor.notifications.some(
-								(notification) => notification.type === "email"
-							)}
+							isChecked={infrastructureMonitor.notify_email}
 							value={user?.email}
 							onChange={(event) => handleNotifications(event, "email")}
 						/>
@@ -361,7 +408,7 @@ const CreateInfrastructureMonitor = () => {
 									isChecked={infrastructureMonitor[metric]}
 									fieldId={METRIC_PREFIX + metric}
 									fieldName={METRIC_PREFIX + metric}
-									fieldValue={infrastructureMonitor[METRIC_PREFIX + metric]}
+									fieldValue={String(infrastructureMonitor[METRIC_PREFIX + metric])}
 									onFieldChange={handleChange}
 									alertUnit={metric == "temperature" ? "°C" : "%"}
 								/>
@@ -408,7 +455,7 @@ const CreateInfrastructureMonitor = () => {
 						onClick={handleCreateInfrastructureMonitor}
 						loading={monitorState?.isLoading}
 					>
-						{t("infrastructureCreateMonitor")}
+						{t(isCreate? "infrastructureCreateMonitor": "infrastructureEditMonitor")}
 					</Button>
 				</Stack>
 			</Stack>
diff --git a/src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx b/src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx
index a5b84cfa4d..dfdf92715d 100644
--- a/src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx
+++ b/src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx
@@ -2,6 +2,11 @@ import { useEffect, useState } from "react";
 import { networkService } from "../../../../main";
 
 const useHardwareMonitorsFetch = ({ monitorId, dateRange }) => {
+
+	// Abort early if creating monitor
+    if (!monitorId) {
+        return { monitor: undefined, isLoading: false, networkError: undefined };
+    }
 	const [isLoading, setIsLoading] = useState(true);
 	const [networkError, setNetworkError] = useState(false);
 	const [monitor, setMonitor] = useState(undefined);
diff --git a/src/Pages/Infrastructure/Details/index.jsx b/src/Pages/Infrastructure/Details/index.jsx
index 0006caf4e6..f7f96f9311 100644
--- a/src/Pages/Infrastructure/Details/index.jsx
+++ b/src/Pages/Infrastructure/Details/index.jsx
@@ -31,6 +31,7 @@ const InfrastructureDetails = () => {
 	const theme = useTheme();
 	const { monitorId } = useParams();
 	const { t } = useTranslation();
+	const isAdmin = useIsAdmin();
 
 	const { isLoading, networkError, monitor } = useHardwareMonitorsFetch({
 		monitorId,
@@ -74,7 +75,7 @@ const InfrastructureDetails = () => {
 			<Breadcrumbs list={BREADCRUMBS} />
 			<MonitorStatusHeader
 				path={"infrastructure"}
-				isAdmin={false}
+				isAdmin={isAdmin}
 				shouldRender={!isLoading}
 				monitor={monitor}
 			/>
diff --git a/src/Routes/index.jsx b/src/Routes/index.jsx
index bf88c92f0a..82d7af7ca5 100644
--- a/src/Routes/index.jsx
+++ b/src/Routes/index.jsx
@@ -148,6 +148,10 @@ const Routes = () => {
 					path="infrastructure/create"
 					element={<InfrastructureCreate />}
 				/>
+				<Route 
+					path="/infrastructure/configure/:monitorId" 
+					element={<InfrastructureCreate />} 
+				/>
 				<Route
 					path="infrastructure/:monitorId"
 					element={<InfrastructureDetails />}
diff --git a/src/Utils/NetworkService.js b/src/Utils/NetworkService.js
index 8924d6466d..58e887f6ed 100644
--- a/src/Utils/NetworkService.js
+++ b/src/Utils/NetworkService.js
@@ -257,14 +257,14 @@ class NetworkService {
 	 * @returns {Promise<AxiosResponse>} The response from the axios PUT request.
 	 */
 	async updateMonitor(config) {
-		const { monitorId, monitor } = config;
-		const updatedFields = {
+		const { monitorId, monitor, updatedFields } = config;
+		const payload = updatedFields ?? {
 			name: monitor.name,
 			description: monitor.description,
 			interval: monitor.interval,
 			notifications: monitor.notifications,
 		};
-		return this.axiosInstance.put(`/monitors/${monitorId}`, updatedFields, {
+		return this.axiosInstance.put(`/monitors/${monitorId}`, payload, {
 			headers: {
 				"Content-Type": "application/json",
 			},
diff --git a/src/Validation/validation.js b/src/Validation/validation.js
index ed0aaf6b86..6e8ff76cbb 100644
--- a/src/Validation/validation.js
+++ b/src/Validation/validation.js
@@ -349,6 +349,12 @@ const infrastructureMonitorValidation = joi.object({
 		"number.base": "Frequency must be a number.",
 		"any.required": "Frequency is required.",
 	}),
+	notifications: joi.array().items(
+		joi.object({
+			type: joi.string().valid("email").required(),
+			address: joi.string().email({ tlds: { allow: false } }).required(),
+		})
+	)
 });
 
 export {
diff --git a/src/locales/gb.json b/src/locales/gb.json
index 5b8bed597a..73ece5bc38 100644
--- a/src/locales/gb.json
+++ b/src/locales/gb.json
@@ -225,11 +225,15 @@
   "incidentsOptionsHeaderLastWeek": "Last week",
   "incidentsOptionsPlaceholderAllServers": "All servers",
   "infrastructureCreateYour": "Create your",
+  "infrastructureEditYour": "Edit your",
   "infrastructureCreateGeneralSettingsDescription": "Here you can select the URL of the host, together with the friendly name and authorization secret to connect to the server agent.",
   "infrastructureServerRequirement": "The server you are monitoring must be running the",
   "infrastructureCustomizeAlerts": "Customize alerts",
   "infrastructureAlertNotificationDescription": "Send a notification to user(s) when thresholds exceed a specified percentage.",
   "infrastructureCreateMonitor": "Create Infrastructure Monitor",
+  "infrastructureEditMonitor": "Save Infrastructure Monitor",
+  "infrastructureMonitorCreated": "Infrastructure monitor created successfully!",
+  "infrastructureMonitorUpdated": "Infrastructure monitor updated successfully!",
   "infrastructureProtocol": "Protocol",
   "infrastructureServerUrlLabel": "Server URL",
   "infrastructureDisplayNameLabel": "Display name",


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>src/locales/gb.json (1)</summary><blockquote>

`159-159`: **Save button text looks ready to go.**

This localization key provides appropriate text for the save button in edit mode. One thought - have we considered a different text for saving edits vs. creating new monitors to better indicate the action?

</blockquote></details>
<details>
<summary>src/Validation/validation.js (1)</summary><blockquote>

`352-357`: **Robust validation for email notifications - nice!**

The validation looks well-structured, ensuring that:
1. Notifications are an array of objects
2. Each notification object has a required `type` field limited to "email"
3. Each notification has a properly formatted email address

However, I'm wondering if we should also validate the maximum number of notifications to prevent potential abuse or performance issues.


Consider adding a maximum limit to the number of notifications:

```diff
 notifications: joi.array().items(
   joi.object({
     type: joi.string().valid("email").required(),
     address: joi.string().email({ tlds: { allow: false } }).required(),
   })
-  )
+  ).max(10) // Limit to a reasonable number
```

</blockquote></details>
<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (2)</summary><blockquote>

`64-64`: **Unused variables from hook**

The destructured variables `isLoading` and `networkError` from `useHardwareMonitorsFetch` are never used in the component, which could lead to confusion about the component's behavior.


Consider one of these approaches:
1. Add loading state handling to improve UX when fetching monitor data
2. Remove the unused variables if they're not needed
```diff
- const { monitor, isLoading, networkError } = isCreate ? {} : useHardwareMonitorsFetch({ monitorId });
+ const { monitor } = isCreate ? {} : useHardwareMonitorsFetch({ monitorId });
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: React Hook "useHardwareMonitorsFetch" is called conditionally. React Hooks must be called in the exact same order in every component render.

(react-hooks/rules-of-hooks)

</details>

</details>

---

`455-456`: **Consider using consistent loading state**

The button shows loading state based on `monitorState?.isLoading` but doesn't account for the `isLoading` from the hook, potentially leading to inconsistent UI feedback.


Consider combining both loading states to provide consistent feedback:
```diff
- loading={monitorState?.isLoading}
+ loading={monitorState?.isLoading || (!isCreate && hookResult?.isLoading)}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1a147775fe65ec92293e08dfd0e3e013f5452f76 and 8df78089e6cd994521c69c1cba2c5c73e0b7cfed.

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js` (1 hunks)
* `src/Pages/Infrastructure/Create/index.jsx` (13 hunks)
* `src/Pages/Infrastructure/Details/index.jsx` (2 hunks)
* `src/Routes/index.jsx` (1 hunks)
* `src/Utils/NetworkService.js` (1 hunks)
* `src/Validation/validation.js` (1 hunks)
* `src/locales/gb.json` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 ESLint</summary>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: React Hook "useHardwareMonitorsFetch" is called conditionally. React Hooks must be called in the exact same order in every component render.

(react-hooks/rules-of-hooks)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (16)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Details/index.jsx (2)</summary>

`34-34`: **Great addition! The isAdmin hook implementation looks good.**

Using the `useIsAdmin()` hook to dynamically determine admin status is a solid improvement over hardcoding the value. This change aligns well with the edit functionality being implemented in this PR.

---

`78-78`: **This dynamic admin check is just what we needed.**

Replacing the hardcoded `false` with the dynamic `isAdmin` variable allows the `MonitorStatusHeader` component to properly reflect the user's admin status, which will control whether the edit functionality is accessible based on permissions.

</details>
<details>
<summary>src/locales/gb.json (1)</summary>

`153-153`: **Good localization key addition for edit mode.**

The new key for edit mode interface text looks good. This supports the edit functionality being introduced in the PR.

</details>
<details>
<summary>src/Routes/index.jsx (1)</summary>

`151-154`: **Nice route configuration for edit functionality.**

The new route properly leverages the existing `InfrastructureCreate` component with a dynamic `monitorId` parameter, maintaining DRY principles. This pattern is consistent with the routes for other monitor types in the application.

</details>
<details>
<summary>src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js (3)</summary>

`97-99`: **Function parameter structure enhancement is well implemented**

The parameter structure change from `(data, thunkApi)` to `({ monitorId, monitor }, thunkApi)` improves code readability by making it clear what data is expected. This change aligns well with the edit functionality requirement.

---

`106-107`: **Good addition of thresholds and secret properties**

Replacing `threshold` with `thresholds` (plural) and adding the `secret` property ensures the update operation includes all necessary fields. This change properly supports the monitor editing functionality.

---

`109-113`: **Clean refactoring of networkService call**

The updated call to `networkService.updateMonitor` now correctly passes the parameters in the expected format, making the code more maintainable and consistent with the updated service method.

</details>
<details>
<summary>src/Utils/NetworkService.js (1)</summary>

`260-267`: **Flexible payload handling implementation looks great**

The changes to the `updateMonitor` method provide better flexibility by:
1. Properly destructuring the parameters
2. Creating a fallback payload when `updatedFields` isn't provided
3. Using the payload in the PUT request

This approach maintains backward compatibility while supporting the new edit functionality for infrastructure monitors.

</details>
<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (8)</summary>

`73-73`: **Good addition of notify_email state**

Adding the `notify_email` state allows for cleaner handling of email notifications preferences, improving the user experience when editing monitors.

---

`87-110`: **Well-implemented form population for edit mode**

The useEffect hook correctly populates the form fields with existing monitor data when in edit mode, including proper conversions for threshold values from decimal to percentage representation. The code also handles potential missing data gracefully.

---

`116-122`: **Improved notification handling logic**

The simplified notification handling code makes the component more maintainable while preserving functionality. The approach to conditionally add the user's email notification is clean and effective.

---

`196-207`: **Clean implementation of create/update logic**

The conditional dispatch based on `isCreate` elegantly handles both creation and update scenarios, with appropriate success messages. This approach minimizes code duplication while providing clear feedback to users.

---

`236-253`: **Enhanced notification handling in handleNotifications function**

The updated function correctly manages the notification list and sets the `notify_email` state based on the checkbox status. This provides a better user experience when editing notification preferences.

---

`258-266`: **Well-structured breadcrumbs for different modes**

The breadcrumb paths are correctly adjusted based on whether the component is in create or edit mode, providing appropriate navigation context to the user.

---

`322-345`: **Good UX consideration for disabling URL in edit mode**

Disabling the URL input field and hiding the protocol selection when in edit mode prevents users from accidentally changing the server address, which could lead to connectivity issues. This is a thoughtful UX decision.

---

`411-411`: **Ensure consistent input value types**

Converting the field value to a string ensures the component handles all input values consistently, preventing potential type-related rendering issues.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-15T07:15:23Z
user: login: llamapreview[bot]
body: # Auto Pull Request Review from LlamaPReview

## 1. Overview
### 1.1 Core Changes
- Primary purpose and scope: Implement the ability to edit settings for existing infrastructure monitors.
- Key components modified: `infrastructureMonitorsSlice.js`, `Create/index.jsx`, `Details/index.jsx`, `Routes/index.jsx`, `NetworkService.js`, `validation.js`, `gb.json`.
- Cross-component impacts: Changes affect Redux state management, routing, API calls, validation, and UI components related to infrastructure monitor creation and details.
- Business value alignment: Improves user experience by allowing in-place modification of monitor configurations, reducing the need to delete and recreate monitors. Aligns with the business need for flexible and dynamic monitoring capabilities.

### 1.2 Technical Architecture 
- System design modifications: The `Create/index.jsx` component now handles both creation and editing of infrastructure monitors, based on the presence of a `monitorId` route parameter.
- Component interaction changes:  The `Create` component fetches existing monitor data when in edit mode and populates the form fields. The `updateInfrastructureMonitor` action in the Redux slice is used for saving changes.
- Integration points impact: The `updateMonitor` function in `NetworkService.js` is modified to handle the update request.
- Dependency changes and implications: No new dependencies were introduced.

## 2. Critical Findings
### 2.1 Must Fix (P0🔴)
**Issue**: Incorrect Threshold Value Conversion
- **Impact**: Thresholds are sent as percentages (e.g., 80) instead of decimals (e.g., 0.8), causing alerts to be 100 times stricter than intended. This could lead to a flood of false-positive alerts.
- **Resolution**: Divide the threshold values by 100 before sending them to the backend.

**Issue**: Incorrect Interval Calculation
- **Impact**: The monitor interval is calculated incorrectly, resulting in a much shorter interval than intended (e.g., 15 seconds instead of 15 minutes). This can overload the monitored server and the monitoring system itself.
- **Resolution**: Use `MS_PER_HOUR = 60 * MS_PER_MINUTE` (3,600,000) for interval calculations.

**Issue**: Authorization Bypass in Edit Mode
- **Impact**: Non-admin users can access the edit functionality by directly navigating to the edit URL, bypassing intended access controls. This could allow unauthorized modification of monitor configurations.
- **Resolution**: Implement an authorization check in `Create/index.jsx` using `useIsAdmin()` and redirect unauthorized users.

### 2.2 Should Fix (P1🟡)
**Issue**: Notification Data Handling
- **Impact**:  Legacy string-format notifications are lost during edits, potentially causing users to miss critical alerts.
- **Suggested Solution**:  Update the notification handling logic to correctly handle both object and string formats during the edit population.

**Issue**: Email Notification State
- **Impact**: The `notify_email` checkbox state is incorrect when non-email alerts exist, leading to a confusing user experience.
- **Suggested Solution**: Update the logic to check for email notifications specifically for the current user's email.

### 2.3 Consider (P2🟢)
**Area**: General Improvements
- **Improvement Opportunity**: Enhance user experience and application robustness.  Suggestions include adding loading states, implementing form dirty state tracking, adding a confirmation modal for unsaved changes, enhancing validation error messages, and adding audit logging for configuration changes.

### 2.4 Summary of Action Items
- **Immediate (P0):** Fix threshold conversion, interval calculation, and authorization bypass.
- **Before Merge (P1):** Correct notification data handling and email notification state.
- **Future Iterations (P2):** Consider general improvements for enhanced usability and robustness.

## 3. Technical Analysis
### 3.1 Code Logic Analysis
📁 **src/Pages/Infrastructure/Create/index.jsx** - **CreateInfrastructureMonitor**
  - Submitted PR Code:
```javascript
    // ... (rest of the component)

    const handleCreateInfrastructureMonitor = async (event) => {
        event.preventDefault();

        // ... (other form building logic)
        let form = {
            // ... (other fields)
            thresholds,
        };

        // ... (validation and dispatch logic)
    };
```
  - Analysis:
    * Current logic: The `handleCreateInfrastructureMonitor` function builds the form data and dispatches either `createInfrastructureMonitor` or `updateInfrastructureMonitor` based on whether `monitorId` is present. The threshold values are directly taken from the component's state.
    * Potential issues: The threshold values are not correctly converted to decimals before being sent to the backend.
    * Edge cases and error handling: The code handles validation errors and displays them to the user.
    * Cross-component impact: Affects the `infrastructureMonitorsSlice.js` and `NetworkService.js`.
    * Business logic considerations: Incorrect threshold values will lead to incorrect alert behavior.
  - LlamaPReview Suggested Improvements:
```javascript
    const handleCreateInfrastructureMonitor = async (event) => {
        event.preventDefault();

        const formattedNotifications = infrastructureMonitor.notifications.map((n) =>
            typeof n === "string" ? { type: "email", address: n } : n
        );

        if (infrastructureMonitor.notify_email) {
            formattedNotifications.push({ type: "email", address: user.email });
        }

        // Build the form
        let form = {
            url: `http${https ? "s" : ""}://` + infrastructureMonitor.url,
            name:
                infrastructureMonitor.name === ""
                    ? infrastructureMonitor.url
                    : infrastructureMonitor.name,
            interval: infrastructureMonitor.interval * MS_PER_HOUR, // Corrected interval calculation
            cpu: infrastructureMonitor.cpu,
            ...(infrastructureMonitor.cpu
                ? { usage_cpu: parseFloat(infrastructureMonitor.usage_cpu) / 100 } // Corrected threshold conversion
                : {}),
            memory: infrastructureMonitor.memory,
            ...(infrastructureMonitor.memory
                ? { usage_memory: parseFloat(infrastructureMonitor.usage_memory) / 100 } // Corrected threshold conversion
                : {}),
            disk: infrastructureMonitor.disk,
            ...(infrastructureMonitor.disk
                ? { usage_disk: parseFloat(infrastructureMonitor.usage_disk) / 100 } // Corrected threshold conversion
                : {}),
            temperature: infrastructureMonitor.temperature,
            ...(infrastructureMonitor.temperature
                ? { usage_temperature: parseFloat(infrastructureMonitor.usage_temperature) / 100 } // Corrected threshold conversion
                : {}),
            secret: infrastructureMonitor.secret,
            notifications: formattedNotifications,
        };

        // ... (rest of the function)

        // Add authorization check for edit mode
        useEffect(() => {
          if (!isCreate && !isAdmin) {
            navigate("/infrastructure");
            createToast({ body: t("unauthorizedAccess") });
          }
        }, [isAdmin, isCreate, navigate, t]);
    };

    // Define MS_PER_HOUR
    const MS_PER_MINUTE = 60 * 1000;
    const MS_PER_HOUR = 60 * MS_PER_MINUTE;
```
  - Improvement rationale:
    * Technical benefits: Corrects the threshold and interval values, ensuring accurate monitor behavior. Adds authorization check to prevent unauthorized access.
    * Business value: Prevents incorrect alerts and unauthorized modifications, improving system reliability and security.
    * Risk assessment: Low risk; these changes are essential for correct functionality.

📁 **src/Pages/Infrastructure/Create/index.jsx** - **useEffect for populating form fields**
  - Submitted PR Code:
```javascript
    useEffect(() => {
        if (isCreate || !monitor) return;

        setInfrastructureMonitor({
            url: monitor.url.replace(/^https?:\/\//, ""),
            name: monitor.name || "",
            notifications: monitor.notifications?.filter(n => typeof n === "object") || [],
            notify_email: (monitor.notifications?.length ?? 0) > 0,
            interval: monitor.interval / MS_PER_MINUTE,
            cpu: monitor.thresholds?.usage_cpu !== undefined,
            usage_cpu: monitor.thresholds?.usage_cpu ? monitor.thresholds.usage_cpu * 100 : "",

            memory: monitor.thresholds?.usage_memory !== undefined,
            usage_memory: monitor.thresholds?.usage_memory ? monitor.thresholds.usage_memory * 100 : "",

            disk: monitor.thresholds?.usage_disk !== undefined,
            usage_disk: monitor.thresholds?.usage_disk ? monitor.thresholds.usage_disk * 100 : "",

            temperature: monitor.thresholds?.usage_temperature !== undefined,
            usage_temperature: monitor.thresholds?.usage_temperature ? monitor.thresholds.usage_temperature * 100 : "",
            secret: monitor.secret || "",
        });
        setHttps(monitor.url.startsWith("https"));
    }, [isCreate, monitor]);
```
  - Analysis:
    * Current logic: Populates the form fields with data from the fetched monitor object when in edit mode.
    * Potential issues: Incorrectly handles legacy string-format notifications and the `notify_email` state. Uses `MS_PER_MINUTE` instead of `MS_PER_HOUR`.
    * Edge cases and error handling: Handles cases where `monitor` or its properties are undefined.
    * Cross-component impact: Affects the display and editing of monitor data.
    * Business logic considerations: Incorrect notification handling can lead to missed alerts.
  - LlamaPReview Suggested Improvements:
```javascript
      useEffect(() => {
        if (isCreate || !monitor) return;

        setInfrastructureMonitor({
            url: monitor.url.replace(/^https?:\/\//, ""),
            name: monitor.name || "",
            notifications: monitor.notifications?.map(n =>
              typeof n === 'string' ? { type: 'email', address: n } : n
            ) || [], // Corrected notification handling
            notify_email: monitor.notifications?.some(n =>
              n.type === 'email' && n.address === user.email
            ) ?? false, // Corrected notify_email logic
            interval: monitor.interval / MS_PER_HOUR, // Corrected interval calculation
            cpu: monitor.thresholds?.usage_cpu !== undefined,
            usage_cpu: monitor.thresholds?.usage_cpu ? monitor.thresholds.usage_cpu * 100 : "",

            memory: monitor.thresholds?.usage_memory !== undefined,
            usage_memory: monitor.thresholds?.usage_memory ? monitor.thresholds.usage_memory * 100 : "",

            disk: monitor.thresholds?.usage_disk !== undefined,
            usage_disk: monitor.thresholds?.usage_disk ? monitor.thresholds.usage_disk * 100 : "",

            temperature: monitor.thresholds?.usage_temperature !== undefined,
            usage_temperature: monitor.thresholds?.usage_temperature ? monitor.thresholds.usage_temperature * 100 : "",
            secret: monitor.secret || "",
        });
        setHttps(monitor.url.startsWith("https"));
    }, [isCreate, monitor, user.email]); // Added user.email to dependency array
```
  - Improvement rationale:
    * Technical benefits: Correctly handles all notification formats and the `notify_email` state. Uses the correct interval calculation.
    * Business value: Ensures accurate data representation and prevents missed alerts.
    * Risk assessment: Low risk; these changes improve data consistency and accuracy.

📁 **src/Utils/NetworkService.js** - **updateMonitor**
  - Submitted PR Code:
```javascript
    async updateMonitor(config) {
        const { monitorId, monitor, updatedFields } = config;
        const payload = updatedFields ?? {
            name: monitor.name,
            description: monitor.description,
            interval: monitor.interval,
            notifications: monitor.notifications,
        };
        return this.axiosInstance.put(`/monitors/${monitorId}`, payload, {
            headers: {
                "Content-Type": "application/json",
            },
        });
    }
```
  - Analysis:
    * Current Logic: The function constructs a payload using either provided `updatedFields` or a default object derived from the `monitor` object.
    * Potential Issues:  The logic for constructing the default payload is redundant and can be simplified. It's better to rely solely on the `updatedFields` passed to the function.
    * Cross-component impact: This function is called by the `updateInfrastructureMonitor` thunk in `infrastructureMonitorsSlice.js`.
    * Business Logic Considerations:  Unnecessary complexity in constructing the payload.

  - LlamaPReview Suggested Improvements:
```javascript
    async updateMonitor({ monitorId, updatedFields }) {
      return this.axiosInstance.put(`/monitors/${monitorId}`, updatedFields, {
          headers: {
              "Content-Type": "application/json",
          },
      });
    }
```
  - Improvement rationale:
    * Technical benefits: Simplifies the function and removes redundant logic. Improves code readability and maintainability.
    * Business value: No direct business value, but improves code quality.
    * Risk assessment: Low risk; this change simplifies the function without altering its core functionality.

### 3.2 Key Quality Aspects 
- System scalability considerations: The changes do not introduce any significant scalability concerns.
- Performance bottlenecks and optimizations: The corrected interval calculation prevents excessive monitoring requests, improving performance.
- Testing strategy and coverage: The PR description mentions self-review and testing. However, adding specific integration tests for the edit flow, threshold conversions, authorization, and notification handling is recommended.
- Documentation needs: No significant documentation changes are required.

## 4. Overall Evaluation
- Technical assessment: The PR introduces valuable functionality for editing infrastructure monitors. However, it contains critical issues related to data handling and authorization that must be addressed.
- Business impact: The PR enhances the user experience and operational efficiency by allowing in-place monitor configuration updates.
- Risk evaluation: The identified critical issues pose a moderate risk to system functionality and security.
- Notable positive aspects and good practices: The PR effectively reuses existing UI components and maintains a consistent validation approach.
- Implementation quality: The implementation is generally good, but requires fixes for the identified issues.
- Final recommendation: Request Changes. The critical issues (P0) must be addressed before merging. The P1 issues should also be addressed before merging.

---
💡 **LlamaPReview Community**
Have feedback on this AI Code review tool? Join our [GitHub Discussions](https://github.com/JetXu-LLM/LlamaPReview-site/discussions) to share your thoughts and help shape the future of LlamaPReview.
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-15T07:21:11Z
user: login: ajhollid
body: Generally looks pretty good!

1.  Hooks should not be called conditionally, early abort in the hook is a better option
2.  Notificaiton handling needs to be more robust since there will be more than one type of notificaction shortly.
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-03-17T05:48:07Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx (1)</summary><blockquote>

`21-21`: **Remove unused statement.**

This line doesn't do anything - it's just referencing `response.data.data` without assigning or using the value.


```diff
-				response.data.data;
```

</blockquote></details>
<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (3)</summary><blockquote>

`64-64`: **Destructured variables not being used.**

The `isLoading` and `networkError` variables are destructured from the hook but never used in the component. You might want to handle these states in the UI.


```diff
-	const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId });
+	const { monitor } = useHardwareMonitorsFetch({ monitorId });
```

Alternatively, if you plan to use these variables later for loading states or error handling:

```jsx
// Show loading state
if (isLoading) return <LoadingSpinner />;

// Show error message
if (networkError) return <ErrorMessage message="Failed to load monitor data" />;
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

---

`411-411`: **Minor improvement: explicit toString conversion may be unnecessary.**

Knees weak, arms are heavy! The explicit String() conversion might be redundant since the value should already be a string from the useState initialization.


```diff
-									fieldValue={String(infrastructureMonitor[METRIC_PREFIX + metric])}
+									fieldValue={infrastructureMonitor[METRIC_PREFIX + metric]}
```

However, if there's a chance the value could be a number in some scenarios, keeping the explicit conversion is safer.

---

`120-122`: **Consider checking if user email already exists in notifications.**

Before pushing the user's email to notifications, you might want to check if it already exists to avoid duplicates.


```diff
		if (infrastructureMonitor.notify_email) {
-			formattedNotifications.push({ type: "email", address: user.email });
+			const userEmailExists = formattedNotifications.some(n => 
+				n.type === "email" && n.address === user.email
+			);
+			if (!userEmailExists) {
+				formattedNotifications.push({ type: "email", address: user.email });
+			}
		}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 8df78089e6cd994521c69c1cba2c5c73e0b7cfed and a006d7194e1a2efa152efe60a696fb011d8b1d3f.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `src/Pages/Infrastructure/Create/index.jsx` (13 hunks)
* `src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 ESLint</summary>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx (1)</summary>

`6-9`: **Added early return for creation mode - good implementation!**

This early return is a solid improvement that prevents unnecessary network calls when creating a new monitor. It aligns with the feedback about conditional hooks in React and makes the code more efficient.

</details>
<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (5)</summary>

`94-94`: **Check notification type specifically for email.**

Mom's spaghetti! This doesn't check if any notifications are of type "email" specifically. As mentioned in the previous review comment, there will be other notification types in the future.


```diff
-			notify_email: (monitor.notifications?.length ?? 0) > 0,
+			notify_email: monitor.notifications?.some(n => n.type === "email") ?? false,
```

---

`87-110`: **Good implementation of form population for edit mode!**

The useEffect implementation to populate form fields is well structured. I particularly like how you're handling the protocol extraction from URLs and the threshold value conversions.

---

`197-199`: **Nice conditional dispatch implementation.**

Clean implementation of handling both create and update scenarios using the same form. The ternary operator makes it concise while maintaining readability.

---

`251-251`: **Improved notification type check.**

Good improvement! You're now setting the `notify_email` state specifically when the notification type is "email".

---

`261-264`: **Elegant breadcrumb path construction.**

The conditional breadcrumb implementation is clean and maintains proper navigation context for both create and edit modes.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-18T18:03:33Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (3)</summary><blockquote>

`58-64`: _⚠️ Potential issue_

**Hooks being conditionally called - needs refactoring**

The `useHardwareMonitorsFetch` hook is being called with a condition check in the component logic. React hooks shouldn't be used conditionally since it can break the order of hooks between renders.




Apply this change to fix the hook call:

```diff
-const { monitorId } = useParams();
-const { t } = useTranslation();	
-
-// Determine if we are creating or editing
-const isCreate = typeof monitorId === "undefined";
-
-// Fetch monitor details if editing
-const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId });
+const { monitorId } = useParams();
+const { t } = useTranslation();	
+
+// Determine if we are creating or editing
+const isCreate = typeof monitorId === "undefined";
+
+// Always call the hook, but abort early if in create mode
+const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId, shouldFetch: !isCreate });
```

You'll need to update the `useHardwareMonitorsFetch` hook to handle the early abort.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

---

`94-94`: _⚠️ Potential issue_

**Notification type check is needed for email notifications**

The code assumes all notifications are email type. This needs to be updated to handle different notification types.




Apply this change to correctly check for email notifications:

```diff
-notify_email: (monitor.notifications?.length ?? 0) > 0,
+notify_email: monitor.notifications?.some(n => n.type === "email" && n.address === user.email) ?? false,
```

---

`116-122`: _🛠️ Refactor suggestion_

**Email notifications handling needs improvement**

Current implementation doesn't properly handle different notification types and just assumes all are email notifications.



```diff
-const formattedNotifications = infrastructureMonitor.notifications.map((n) =>
-   typeof n === "string" ? { type: "email", address: n } : n
-);
-
-if (infrastructureMonitor.notify_email) {
-   formattedNotifications.push({ type: "email", address: user.email });
-}

+// Keep existing notifications of all types
+const formattedNotifications = infrastructureMonitor.notifications.filter(n => 
+   typeof n === "object" && n.type && n.address
+);
+
+// Handle email notifications specifically
+if (infrastructureMonitor.notify_email) {
+   // Check if user email already exists in the email notifications
+   const hasUserEmail = formattedNotifications.some(n => 
+      n.type === "email" && n.address === user.email
+   );
+   
+   // Add user email only if it doesn't exist already
+   if (!hasUserEmail) {
+      formattedNotifications.push({ type: "email", address: user.email });
+   }
+}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (2)</summary><blockquote>

`64-64`: **Unused variables from hook destructuring**

The variables `isLoading` and `networkError` are assigned values but never used in the component.


Either use these variables for loading state and error handling or remove them from the destructuring:

```diff
-const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId });
+const { monitor } = useHardwareMonitorsFetch({ monitorId });
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

---

`87-110`: **Ensure state isn't set on unmounted component**

The `useEffect` hook might set state after the component is unmounted if the user navigates away quickly, causing React warnings.


Add cleanup to prevent state updates after unmount:

```diff
useEffect(() => {
    if (isCreate || !monitor) return;
+
+    let isMounted = true;
+
+    if (isMounted) {
        setInfrastructureMonitor({
            url: monitor.url.replace(/^https?:\/\//, ""),
            name: monitor.name || "",
            notifications: monitor.notifications?.filter(n => typeof n === "object") || [],
            notify_email: (monitor.notifications?.length ?? 0) > 0,
            interval: monitor.interval / MS_PER_MINUTE,
            cpu: monitor.thresholds?.usage_cpu !== undefined,
            usage_cpu: monitor.thresholds?.usage_cpu ? monitor.thresholds.usage_cpu * 100 : "",
        
            memory: monitor.thresholds?.usage_memory !== undefined,
            usage_memory: monitor.thresholds?.usage_memory ? monitor.thresholds.usage_memory * 100 : "",
        
            disk: monitor.thresholds?.usage_disk !== undefined,
            usage_disk: monitor.thresholds?.usage_disk ? monitor.thresholds.usage_disk * 100 : "",
        
            temperature: monitor.thresholds?.usage_temperature !== undefined,
            usage_temperature: monitor.thresholds?.usage_temperature ? monitor.thresholds.usage_temperature * 100 : "",
            secret: monitor.secret || "",
        });
        setHttps(monitor.url.startsWith("https"));
+    }
+
+    return () => {
+        isMounted = false;
+    };
}, [isCreate, monitor]);
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between a006d7194e1a2efa152efe60a696fb011d8b1d3f and 958b51b7119a1d6c390129647a56121e238e55e6.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js` (1 hunks)
* `src/Pages/Infrastructure/Create/index.jsx` (13 hunks)
* `src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx` (1 hunks)
* `src/Pages/Infrastructure/Details/index.jsx` (2 hunks)
* `src/Routes/index.jsx` (1 hunks)
* `src/Utils/NetworkService.js` (1 hunks)
* `src/Validation/validation.js` (1 hunks)
* `src/locales/gb.json` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (6)</summary>

* src/Routes/index.jsx
* src/Pages/Infrastructure/Details/index.jsx
* src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx
* src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js
* src/Validation/validation.js
* src/Utils/NetworkService.js

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 ESLint</summary>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (9)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (7)</summary>

`196-200`: **Good implementation of the edit/create logic**

The implementation of handling both create and update operations with a conditional dispatch based on `isCreate` is well done.

---

`237-252`: **Improved notification handling with type check**

This implementation now correctly handles different notification types by checking both type and address in the notification object.

---

`261-264`: **Well-structured conditional breadcrumb paths**

The breadcrumb paths are correctly structured based on whether the user is creating or editing a monitor.

---

`284-284`: **Good use of internationalization**

The component properly uses the translation function with appropriate keys for create vs. edit modes.

---

`323-345`: **Conditional rendering for create-only fields**

Disabling the URL input field when editing and conditionally rendering the protocol selection buttons is a good UX decision.

---

`412-412`: **Fixed potential type issues with field values**

Converting numeric values to string when setting field values prevents React warnings about controlled/uncontrolled inputs.

---

`458-458`: **Correct use of internationalization for button text**

The button text correctly changes based on whether the user is creating or editing using translation keys.

</details>
<details>
<summary>src/locales/gb.json (2)</summary>

`153-154`: **Good addition of edit-specific localization strings**

The addition of "Edit your" and "Save Infrastructure Monitor" strings complements the new edit functionality.

---

`239-269`: **Comprehensive notification system localization added**

The addition of a full notifications object with platform-specific strings indicates solid preparation for multi-platform notification support.



The structured approach with nested objects for different platforms (Slack, Discord, Telegram, Webhook) shows good organization and forward thinking.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-18T18:27:40Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (1)</summary><blockquote>

`64-64`: **Unused variables need to be handled**

The destructured variables `isLoading` and `networkError` from useHardwareMonitorsFetch are declared but never used.


Either use them for loading/error states or destructure only what you need:

```diff
- const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId });
+ const { monitor } = useHardwareMonitorsFetch({ monitorId });
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 958b51b7119a1d6c390129647a56121e238e55e6 and 7dfc9bff5fe5eadf73a38666774095afe5d82bd9.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js` (1 hunks)
* `src/Pages/Infrastructure/Create/index.jsx` (13 hunks)
* `src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx` (1 hunks)
* `src/Pages/Infrastructure/Details/index.jsx` (2 hunks)
* `src/Routes/index.jsx` (1 hunks)
* `src/Utils/NetworkService.js` (1 hunks)
* `src/Validation/validation.js` (1 hunks)
* `src/locales/gb.json` (5 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (6)</summary>

* src/Validation/validation.js
* src/Routes/index.jsx
* src/Pages/Infrastructure/Details/index.jsx
* src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js
* src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx
* src/Utils/NetworkService.js

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (2)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx (2) (2)</summary>

* `useHardwareMonitorsFetch` (4-37)
* `monitor` (12-12)

</details>
<details>
<summary>src/Features/InfrastructureMonitors/infrastructureMonitorsSlice.js (2) (2)</summary>

* `updateInfrastructureMonitor` (97-126)
* `updateInfrastructureMonitor` (97-126)

</details>

</blockquote></details>

</details><details>
<summary>🪛 ESLint</summary>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>
<details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>src/locales/gb.json</summary>

[error] 112-112: The key actions was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

---

[error] 181-181: The key status was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

---

[error] 185-185: The key host was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (10)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (7)</summary>

`57-64`: **Good implementation of the edit functionality 👍**

You've correctly implemented the logic to determine whether we're in create or edit mode using the monitorId parameter. The useHardwareMonitorsFetch hook is properly used to fetch the existing monitor data.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

---

`87-110`: **Good form population logic**

The useEffect hook properly populates the form fields when in edit mode, including converting threshold values from decimals back to percentages. The early return when `isCreate` is true or monitor data is not available is clean.

---

`116-122`: **Notification handling looks good**

The formatting of notification objects and conditional adding of the current user's email based on the notify_email flag works well.

---

`197-199`: **Clean implementation of create/update logic**

The conditional dispatching of either create or update actions based on the `isCreate` flag is clean and concise.

---

`237-252`: **Hook conditional call should be avoided**

The implementation follows the previous review comment about checking notification types, but there's still an issue with how hooks are called.


React doesn't always work as expected if hooks are conditionally called. Better to add a check to the `useHardwareFetch` hook to abort early if `isCreate === true`

This should throw an error in your linter, make sure you've got it on and set up for React

---

`323-323`: **Good UI handling for edit mode**

Disabling the URL input when editing and conditionally rendering the protocol options are good UI decisions that prevent confusion.




Also applies to: 325-345

---

`411-411`: **Ensure consistent value types**

Using `String()` to ensure the field value is a string is a good practice to prevent type issues in controlled components.

</details>
<details>
<summary>src/locales/gb.json (3)</summary>

`6-6`: **Capitalization change for consistency**

The capitalization change from "Sign Up" to "Sign up" improves consistency with other UI elements.

---

`244-275`: **Great implementation of notification strings**

The structured organization of notification strings by platform type is excellent. This will make it easier to maintain and extend notification capabilities in the future.

---

`325-325`: **Good addition of edit-specific strings**

Adding separate strings for edit mode ("infrastructureEditYour" and "infrastructureEditMonitor") improves the user experience by providing context-appropriate text.




Also applies to: 331-332

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-19T14:37:56Z
user: login: ajhollid
body: Two minor changes and we're good to go here I think :+1: 
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T19:39:32Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (1)</summary><blockquote>

`57-64`: **Unused variables in hook destructuring.**

You're properly determining the mode based on monitor ID presence, but the `isLoading` and `networkError` variables from the hook are never used in the component.


```diff
- const { monitor, isLoading, networkError } = useHardwareMonitorsFetch({ monitorId });
+ const { monitor } = useHardwareMonitorsFetch({ monitorId });
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 ESLint</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: .coderabbit.yaml**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 143d3ea7c6ebbd220cb33c0e9eb33f4196dffa6d and 0a1f47c532b2ee2d41ab29f40689a9e4eb7b1ace.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `src/Pages/Infrastructure/Create/index.jsx` (13 hunks)
* `src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx` (1 hunks)
* `src/Utils/NetworkService.js` (1 hunks)
* `src/locales/gb.json` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx
* src/Utils/NetworkService.js

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 ESLint</summary>

<details>
<summary>src/Pages/Infrastructure/Create/index.jsx</summary>

[error] 64-64: 'isLoading' is assigned a value but never used.

(no-unused-vars)

---

[error] 64-64: 'networkError' is assigned a value but never used.

(no-unused-vars)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (15)</summary><blockquote>

<details>
<summary>src/locales/gb.json (2)</summary>

`228-228`: **Good addition of localization key for edit mode.**

This localization key properly supports the edit mode for infrastructure monitors, which is a key part of this PR.

---

`234-236`: **Great job adding meaningful success messages for both operations.**

The addition of separate success messages for creating versus updating infrastructure monitors improves the user experience by providing appropriate feedback.

</details>
<details>
<summary>src/Pages/Infrastructure/Create/index.jsx (13)</summary>

`3-4`: **Imports properly updated for new functionality.**

The additions of `useParams` for route parameter extraction and `useEffect` for handling form population in edit mode are appropriate for the added functionality.

---

`9-10`: **Good imports for edit functionality.**

The addition of the `updateInfrastructureMonitor` action and `useHardwareMonitorsFetch` hook are necessary for the edit functionality to work correctly.

---

`73-73`: **Good addition of notify_email state.**

Adding this state property helps keep track of email notification preferences independently.

---

`87-110`: **Excellent implementation of form population for edit mode.**

The useEffect hook correctly populates the form with existing monitor data when in edit mode, with proper handling of the URL protocol and values formatting. The early return when in create mode or no monitor is available addresses the previous issue with conditional hook execution.

---

`116-122`: **Improved notification handling!**

The notifications are now properly formatted to handle both string email addresses and structured notification objects. The addition of the current user's email when `notify_email` is checked is a nice touch for usability.

---

`197-203`: **Clean implementation of create/update logic!**

The conditional dispatch based on `isCreate` flag is well-implemented, and the success toast uses the appropriate localized message based on the operation type.

---

`237-252`: **Enhanced notification handling with email type check.**

The modification to the notification handling now properly manages the `notify_email` state when the notification type is specifically "email". This addresses a previous review comment about preparing for multiple notification types.

---

`261-264`: **Well-structured breadcrumb navigation.**

The breadcrumb navigation now correctly reflects whether the user is in create or edit mode, providing appropriate navigation paths in each case.

---

`284-284`: **Good use of conditional localization.**

Using the appropriate localization key based on whether we're in create or edit mode improves the user experience by providing context-appropriate text.

---

`323-323`: **Smart decision to disable URL field in edit mode.**

Disabling the URL field in edit mode prevents users from changing the fundamental identifier of the monitor, which could cause data integrity issues.

---

`325-345`: **Good conditional rendering of protocol selection.**

Only showing the protocol buttons in create mode makes sense since changing the protocol on an existing monitor would likely break the connection.

---

`411-411`: **Field value properly converted to string.**

Converting the field value to a string ensures consistent behavior in the form input, preventing potential type-related issues.

---

`458-458`: **Appropriate button text based on operation.**

Using different button text for create versus edit operations improves clarity for the user about what action they're taking.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-19T20:05:20Z
user: login: ajhollid
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-19T20:08:02Z

Review comments:
diff_hunk: @@ -53,7 +54,14 @@ const CreateInfrastructureMonitor = () => {
 	const monitorState = useSelector((state) => state.infrastructureMonitor);
 	const dispatch = useDispatch();
 	const navigate = useNavigate();
-	const { t } = useTranslation();
+	const { monitorId } = useParams();
+	const { t } = useTranslation();	
+
+	// Determine if we are creating or editing
+	const isCreate = typeof monitorId === "undefined";
+
+	// Fetch monitor details if editing
+	const { monitor, isLoading, networkError } = isCreate ? {} : useHardwareMonitorsFetch({ monitorId });
path: src/Pages/Infrastructure/Create/index.jsx
user: login: ajhollid
body: React doesn't always work as expected if hooks are conditionally called.  Better to add a check to the `userHardwareFetch` hook to abort early if `isCreate === true`

This should throw an error in your linter, make sure you've got it on and set up for React
created_at: 2025-03-17T05:37:24Z
author_association: COLLABORATOR
diff_hunk: @@ -74,10 +83,44 @@ const CreateInfrastructureMonitor = () => {
 		secret: "",
 	});
 
+	// Populate form fields if editing
+	useEffect(() => {
+		if (isCreate || !monitor) return;
+
+		setInfrastructureMonitor({
+			url: monitor.url.replace(/^https?:\/\//, ""),
+			name: monitor.name || "",
+			notifications: monitor.notifications?.filter(n => typeof n === "object") || [],
+			notify_email: (monitor.notifications?.length ?? 0) > 0,
path: src/Pages/Infrastructure/Create/index.jsx
user: login: ajhollid
body: There will be other types of notifictions besides email in the near future, we need check this only if the notiication type is "email"
created_at: 2025-03-17T05:45:36Z
author_association: COLLABORATOR
diff_hunk: @@ -81,13 +56,100 @@
 	"authRegisterCreateSuperAdminAccount": "Create your Super admin account to get started",
 	"authRegisterSignUpWithEmail": "Sign up with Email",
 	"authRegisterBySigningUp": "By signing up, you agree to our",
+	"distributedStatusHeaderText": "Real-time, real-device coverage",
+	"distributedStatusSubHeaderText": "Powered by millions devices worldwide, view a system performance by global region, country or city",
+	"settingsGeneralSettings": "General settings",
+	"settingsDisplayTimezone": "Display timezone",
+	"settingsDisplayTimezoneDescription": "The timezone of the dashboard you publicly display.",
+	"settingsAppearance": "Appearance",
+	"settingsAppearanceDescription": "Switch between light and dark mode, or change user interface language",
+	"settingsThemeMode": "Theme Mode",
+	"settingsLanguage": "Language",
+	"settingsDistributedUptime": "Distributed uptime",
+	"settingsDistributedUptimeDescription": "Enable/disable distributed uptime monitoring.",
+	"settingsEnabled": "Enabled",
+	"settingsDisabled": "Disabled",
+	"settingsHistoryAndMonitoring": "History and monitoring",
+	"settingsHistoryAndMonitoringDescription": "Define here for how long you want to keep the data. You can also remove all past data.",
+	"settingsTTLLabel": "The days you want to keep monitoring history.",
+	"settingsTTLOptionalLabel": "0 for infinite",
+	"settingsClearAllStats": "Clear all stats. This is irreversible.",
+	"settingsClearAllStatsButton": "Clear all stats",
+	"settingsClearAllStatsDialogTitle": "Do you want to clear all stats?",
+	"settingsClearAllStatsDialogDescription": "Once deleted, your monitors cannot be retrieved.",
+	"settingsClearAllStatsDialogConfirm": "Yes, clear all stats",
+	"settingsDemoMonitors": "Demo monitors",
+	"settingsDemoMonitorsDescription": "Here you can add and remove demo monitors.",
+	"settingsAddDemoMonitors": "Add demo monitors",
+	"settingsAddDemoMonitorsButton": "Add demo monitors",
+	"settingsRemoveAllMonitors": "Remove all monitors",
+	"settingsRemoveAllMonitorsButton": "Remove all monitors",
+	"settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?",
+	"settingsRemoveAllMonitorsDialogConfirm": "Yes, clear all monitors",
+	"settingsWallet": "Wallet",
+	"settingsWalletDescription": "Connect your wallet here. This is required for the Distributed Uptime monitor to connect to multiple nodes globally.",
+	"settingsAbout": "About",
+	"settingsDevelopedBy": "Developed by Bluewave Labs.",
+	"settingsSave": "Save",
+	"settingsSuccessSaved": "Settings saved successfully",
+	"settingsFailedToSave": "Failed to save settings",
+	"settingsStatsCleared": "Stats cleared successfully",
+	"settingsFailedToClearStats": "Failed to clear stats",
+	"settingsDemoMonitorsAdded": "Successfully added demo monitors",
+	"settingsFailedToAddDemoMonitors": "Failed to add demo monitors",
+	"settingsMonitorsDeleted": "Successfully deleted all monitors",
+	"settingsFailedToDeleteMonitors": "Failed to delete all monitors",
+	"starPromptTitle": "Star Checkmate",
+	"starPromptDescription": "See the latest releases and help grow the community on GitHub",
+	"https": "HTTPS",
+	"http": "HTTP",
+	"monitor": "monitor",
+	"aboutus": "About Us",
+	"signUP": "Sign Up",
+	"now": "Now",
+	"createYour": "Create your",
+	"createMonitor": "Create monitor",
+	"actions": "Actions",
path: src/locales/gb.json
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Duplicate keys detected in locale file**

There are duplicate keys in the locale file: "actions" (line 112), "status" (line 181), and "host" (line 185). Only the last definition will take effect.


Remove or rename the duplicate keys to ensure all translations are correctly applied:

```diff
- "actions": "Actions",
...
- "status": "Status",
...
- "host": "Host",
```

Consider using more specific keys like "monitorActions", "monitorStatus", and "monitorHost" if these represent different contexts.


Also applies to: 181-181, 185-185

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 112-112: The key actions was already declared.

This where a duplicated key was declared again.

If a key is defined multiple times, only the last definition takes effect. Previous definitions are ignored.

(lint/suspicious/noDuplicateObjectKeys)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commits 5466d38 to 143d3ea
created_at: 2025-03-19T14:37:55Z
author_association: NONE
diff_hunk: @@ -2,6 +2,11 @@ import { useEffect, useState } from "react";
 import { networkService } from "../../../../main";
 
 const useHardwareMonitorsFetch = ({ monitorId, dateRange }) => {
+
+	// Abort early if creating monitor
+    if (!monitorId) {
+        return { monitor: null, isLoading: false, networkError: null };
path: src/Pages/Infrastructure/Details/Hooks/useHardwareMonitorsFetch.jsx
user: login: ajhollid
body: Can you set `monitor` and `networkError` to `undefined` please?  That's our standard empty value
created_at: 2025-03-19T19:38:14Z
author_association: COLLABORATOR
diff_hunk: @@ -149,12 +193,17 @@ const CreateInfrastructureMonitor = () => {
 			thresholds,
 		};
 
-		const action = await dispatch(createInfrastructureMonitor({ monitor: form }));
+		// Handle create or update
+		const action = isCreate
+			? await dispatch(createInfrastructureMonitor({ monitor: form }))
+			: await dispatch(updateInfrastructureMonitor({ monitorId, monitor: form }));
 		if (action.meta.requestStatus === "fulfilled") {
-			createToast({ body: "Infrastructure monitor created successfully!" });
+			createToast({
+				body: isCreate ? "Infrastructure monitor created successfully!" : "Infrastructure monitor updated successfully!",
path: src/Pages/Infrastructure/Create/index.jsx
user: login: ajhollid
body: Can you extract these strings please?  Thanks
created_at: 2025-03-19T19:38:55Z
author_association: COLLABORATOR
diff_hunk: @@ -103,6 +146,7 @@ const CreateInfrastructureMonitor = () => {
 				? { usage_temperature: infrastructureMonitor.usage_temperature }
 				: {}),
 			secret: infrastructureMonitor.secret,
+			notifications: formattedNotifications,
path: src/Pages/Infrastructure/Create/index.jsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Inconsistency in notifications field usage between form objects.**

There's still an inconsistency between line 149 (which uses `formattedNotifications`) and line 192 (which uses `infrastructureMonitor.notifications`). This could lead to different notification data being used in different parts of the form submission process.


```diff
form = {
    ...rest,
    description: form.name,
    teamId: user.teamId,
    userId: user._id,
    type: "hardware",
-   notifications: infrastructureMonitor.notifications,
+   notifications: formattedNotifications,
    thresholds,
};
```


Also applies to: 192-192

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-19T20:05:19Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-15T07:15:19Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
This pull request updates several files to enhance the handling of infrastructure monitors. The modifications include restructuring parameters and payloads for update operations, differentiating between create and edit modes, extending validation rules, and enhancing localization. A new route for configuring monitors is added, and the admin state is now dynamically determined on the details page. The changes are spread across slice functions, UI components, route definitions, network service logic, validation schema, and locale files.

## Changes

| File(s) | Change Description |
|---------|--------------------|
| `src/Features/.../infrastructureMonitorsSlice.js`<br>`src/Utils/NetworkService.js` | Updated update functions by restructuring parameters (now using `{ monitorId, monitor }`), replacing the `threshold` property with `thresholds`, adding a `secret` property, and modifying payload creation for the PUT request. |
| `src/Pages/.../Create/index.jsx` | Enhanced the monitor creation page to handle both creation and editing. Added `useParams` to check for `monitorId`, introduced a new `notify_email` state, used `useEffect` to prefill data, updated the submission handler (`handleCreateInfrastructureMonitor`), and added the `useHardwareMonitorsFetch` hook. |
| `src/Pages/.../Details/index.jsx` | Added an `isAdmin` variable using the `useIsAdmin()` hook and passed it to the `MonitorStatusHeader` component, allowing dynamic admin status rendering. |
| `src/Routes/index.jsx` | Added a new route with path `/infrastructure/configure/:monitorId`, which renders the `InfrastructureCreate` component. |
| `src/Validation/validation.js` | Extended the `infrastructureMonitorValidation` schema by adding a new `notifications` property. This property is an array of objects requiring a `type` (only "email") and an `address` with email validation. |
| `src/locales/gb.json` | Inserted numerous new localization keys to enhance user interface elements related to infrastructure management and notifications. |
| `src/Pages/.../Details/Hooks/useHardwareMonitorsFetch.jsx` | Introduced an early return condition for the `useHardwareMonitorsFetch` hook to prevent unnecessary data fetching when `monitorId` is not provided. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant U as User
    participant B as Browser
    participant P as Create/Edit Page
    participant S as Monitor Slice
    participant N as NetworkService
    participant SV as Server

    U->>B: Navigate to /infrastructure/configure/:monitorId
    B->>P: Render InfrastructureCreate Component
    P->>P: Retrieve monitorId with useParams
    alt Edit Mode (monitorId exists)
        P->>P: Load existing monitor data and prefill form (including notify_email)
    else Create Mode
        P->>P: Display empty form for new monitor
    end
    U->>P: Submit form data
    alt Edit Mode
        P->>S: Dispatch updateInfrastructureMonitor({ monitorId, monitor })
    else Create Mode
        P->>S: Dispatch createInfrastructureMonitor({ monitor data })
    end
    S->>N: Call updateMonitor(payload) if update
    N->>SV: Send PUT request with payload
    SV-->>N: Return update confirmation
    N-->>S: Pass response back
    S-->>P: Deliver result to UI
    P->>U: Display success or error message
```

## Possibly related PRs
- bluewave-labs/Checkmate#1787: The changes in the main PR, specifically the modifications to the `updateInfrastructureMonitor` function, are related to the removal of the `authToken` from the destructured data in the `infrastructureMonitorsSlice.js`, which aligns with the overall theme of the retrieved PR that also focuses on eliminating the need for passing the `authToken` in various components and thunks.

## Suggested reviewers
- ajhollid

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡🧪 Multi-step agentic review comment chat (experimental)</summary>
> 
> - We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
> 						- To enable this feature, set early_access to true under in the settings.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=bluewave-labs/Checkmate&utm_content=1933):

> ‼️ **IMPORTANT**
> Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: gorkem-bwl
created_at: 2025-03-15T16:28:07Z
body: Thanks @vishnusn77 - UI wise looks good to me!
author_association: CONTRIBUTOR
user: login: ajhollid
created_at: 2025-03-15T16:30:18Z
body: Yep looks good visually! @vishnusn77 I'll review as soon as possible, it's a bigger PR so might take me a little bit, thanks for your patience! 
author_association: COLLABORATOR
user: login: vishnusn77
created_at: 2025-03-18T18:00:44Z
body: > Generally looks pretty good!
> 
> 1. Hooks should not be called conditionally, early abort in the hook is a better option
> 2. Notificaiton handling needs to be more robust since there will be more than one type of notificaction shortly.

I have made requested changes @ajhollid 
author_association: CONTRIBUTOR
user: login: vishnusn77
created_at: 2025-03-19T20:03:30Z
body: > Two minor changes and we're good to go here I think 👍

Done 👍
author_association: CONTRIBUTOR