From 46579cd176cddce5521ab4b7d83540302ec7a483 Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Fri, 8 Aug 2025 13:44:44 +0100 Subject: [PATCH 1/9] feat: allow updating monitor URL and type via Configure --- client/src/Hooks/monitorHooks.js | 1 + .../src/Pages/Infrastructure/Create/index.jsx | 49 ++++++++++--------- server/src/validation/joi.js | 1 + 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/client/src/Hooks/monitorHooks.js b/client/src/Hooks/monitorHooks.js index 616a37877..40641b722 100644 --- a/client/src/Hooks/monitorHooks.js +++ b/client/src/Hooks/monitorHooks.js @@ -357,6 +357,7 @@ const useUpdateMonitor = () => { expectedValue: monitor.expectedValue, ignoreTlsErrors: monitor.ignoreTlsErrors, jsonPath: monitor.jsonPath, + url: monitor.url, ...(monitor.type === "port" && { port: monitor.port }), ...(monitor.type === "hardware" && { thresholds: monitor.thresholds, diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx index ae95cce33..23e8c45e4 100644 --- a/client/src/Pages/Infrastructure/Create/index.jsx +++ b/client/src/Pages/Infrastructure/Create/index.jsx @@ -234,6 +234,7 @@ const CreateInfrastructureMonitor = () => { form = { ...(isCreate ? {} : { _id: monitorId }), ...rest, + url: `http${https ? "s" : ""}://` + infrastructureMonitor.url, description: form.name, type: "hardware", notifications: infrastructureMonitor.notifications, @@ -470,31 +471,31 @@ const CreateInfrastructureMonitor = () => { onChange={onChange} error={errors["url"] ? true : false} helperText={errors["url"]} - disabled={!isCreate} + disabled={false} /> - {isCreate && ( - - - - - - - )} + + + + + + + + Date: Fri, 8 Aug 2025 14:15:07 +0100 Subject: [PATCH 2/9] fix(client): add client-side URL validation to updateMonitor hook --- client/src/Hooks/monitorHooks.js | 5 +++++ client/src/Pages/Infrastructure/Create/index.jsx | 3 ++- client/src/Utils/url.js | 13 +++++++++++++ server/src/validation/joi.js | 5 ++++- 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 client/src/Utils/url.js diff --git a/client/src/Hooks/monitorHooks.js b/client/src/Hooks/monitorHooks.js index 40641b722..03345b9cb 100644 --- a/client/src/Hooks/monitorHooks.js +++ b/client/src/Hooks/monitorHooks.js @@ -5,6 +5,7 @@ import { useTheme } from "@emotion/react"; import { useMonitorUtils } from "./useMonitorUtils"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; +import { validateUrl } from "../Utils/url"; const useFetchMonitorsWithSummary = ({ types, monitorUpdateTrigger }) => { const [isLoading, setIsLoading] = useState(false); @@ -344,8 +345,12 @@ const useDeleteMonitor = () => { const useUpdateMonitor = () => { const [isLoading, setIsLoading] = useState(false); + const navigate = useNavigate(); const updateMonitor = async ({ monitor, redirect }) => { + if (monitor.url && !validateUrl(monitor.url)) { + throw new Error("Invalid URL format"); + } try { setIsLoading(true); const updatedFields = { diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx index 23e8c45e4..405c40e19 100644 --- a/client/src/Pages/Infrastructure/Create/index.jsx +++ b/client/src/Pages/Infrastructure/Create/index.jsx @@ -24,6 +24,7 @@ import { useSelector } from "react-redux"; import { useState, useEffect } from "react"; import { useTheme } from "@emotion/react"; import { useTranslation } from "react-i18next"; +import { normalizeUrl } from "../../../Utils/url"; import { useCreateMonitor, useDeleteMonitor, @@ -234,7 +235,7 @@ const CreateInfrastructureMonitor = () => { form = { ...(isCreate ? {} : { _id: monitorId }), ...rest, - url: `http${https ? "s" : ""}://` + infrastructureMonitor.url, + url: normalizeUrl(infrastructureMonitor.url, https), description: form.name, type: "hardware", notifications: infrastructureMonitor.notifications, diff --git a/client/src/Utils/url.js b/client/src/Utils/url.js new file mode 100644 index 000000000..963c1bd3c --- /dev/null +++ b/client/src/Utils/url.js @@ -0,0 +1,13 @@ +export const normalizeUrl = (input, useHttps) => { + const cleaned = input.replace(/^(https?:\/\/)/i, ""); + return `http${useHttps ? "s" : ""}://${cleaned}`; +}; + +export const validateUrl = (url) => { + try { + new URL(url); + return true; + } catch { + return false; + } +}; diff --git a/server/src/validation/joi.js b/server/src/validation/joi.js index 34ef00cf9..ab9778e30 100755 --- a/server/src/validation/joi.js +++ b/server/src/validation/joi.js @@ -181,7 +181,10 @@ const createMonitorsBodyValidation = joi.array().items( ); const editMonitorBodyValidation = joi.object({ - url: joi.string(), + url: joi + .string() + .uri({ scheme: ["http", "https"] }) + .optional(), name: joi.string(), description: joi.string(), interval: joi.number(), From 38fe814786819a228c5eca212c7a3ad00564cfb1 Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Fri, 8 Aug 2025 14:23:10 +0100 Subject: [PATCH 3/9] refactor(client): harden URL normalization and validation utilities --- client/src/Utils/url.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/client/src/Utils/url.js b/client/src/Utils/url.js index 963c1bd3c..5fd73eb31 100644 --- a/client/src/Utils/url.js +++ b/client/src/Utils/url.js @@ -1,12 +1,14 @@ export const normalizeUrl = (input, useHttps) => { - const cleaned = input.replace(/^(https?:\/\/)/i, ""); + const raw = String(input ?? "").trim(); + const cleaned = raw.replace(/^(?:https?:)?\/\//i, ""); return `http${useHttps ? "s" : ""}://${cleaned}`; }; export const validateUrl = (url) => { + if (typeof url !== "string" || !url.trim()) return false; try { - new URL(url); - return true; + const u = new URL(url.trim()); + return u.protocol === "http:" || u.protocol === "https:"; } catch { return false; } From da4b5c9f36fc38b78ecfdc61b3562ed8b3084bdc Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Fri, 8 Aug 2025 18:22:33 +0100 Subject: [PATCH 4/9] refactor(client): remove redundant client-side URL validation, rely on Joi --- client/src/Hooks/monitorHooks.js | 4 ---- client/src/Pages/Infrastructure/Create/index.jsx | 1 - client/src/Utils/url.js | 10 ---------- 3 files changed, 15 deletions(-) diff --git a/client/src/Hooks/monitorHooks.js b/client/src/Hooks/monitorHooks.js index 03345b9cb..eb1318c4b 100644 --- a/client/src/Hooks/monitorHooks.js +++ b/client/src/Hooks/monitorHooks.js @@ -5,7 +5,6 @@ import { useTheme } from "@emotion/react"; import { useMonitorUtils } from "./useMonitorUtils"; import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import { validateUrl } from "../Utils/url"; const useFetchMonitorsWithSummary = ({ types, monitorUpdateTrigger }) => { const [isLoading, setIsLoading] = useState(false); @@ -348,9 +347,6 @@ const useUpdateMonitor = () => { const navigate = useNavigate(); const updateMonitor = async ({ monitor, redirect }) => { - if (monitor.url && !validateUrl(monitor.url)) { - throw new Error("Invalid URL format"); - } try { setIsLoading(true); const updatedFields = { diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx index 405c40e19..57b512968 100644 --- a/client/src/Pages/Infrastructure/Create/index.jsx +++ b/client/src/Pages/Infrastructure/Create/index.jsx @@ -472,7 +472,6 @@ const CreateInfrastructureMonitor = () => { onChange={onChange} error={errors["url"] ? true : false} helperText={errors["url"]} - disabled={false} /> { const cleaned = raw.replace(/^(?:https?:)?\/\//i, ""); return `http${useHttps ? "s" : ""}://${cleaned}`; }; - -export const validateUrl = (url) => { - if (typeof url !== "string" || !url.trim()) return false; - try { - const u = new URL(url.trim()); - return u.protocol === "http:" || u.protocol === "https:"; - } catch { - return false; - } -}; From 81ec448d257e8ff132cf51a01d11c72f9c5cf3da Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Sat, 9 Aug 2025 16:49:06 +0100 Subject: [PATCH 5/9] fix(validation): use Joi for frontend & backend URL validation with hostOnly to prevent path --- .../src/Pages/Infrastructure/Create/index.jsx | 39 +++++++++++-------- client/src/Utils/url.js | 5 --- client/src/Validation/validation.js | 25 +++++++----- server/src/validation/joi.js | 6 ++- 4 files changed, 44 insertions(+), 31 deletions(-) delete mode 100644 client/src/Utils/url.js diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx index 57b512968..9ded4e10f 100644 --- a/client/src/Pages/Infrastructure/Create/index.jsx +++ b/client/src/Pages/Infrastructure/Create/index.jsx @@ -24,7 +24,6 @@ import { useSelector } from "react-redux"; import { useState, useEffect } from "react"; import { useTheme } from "@emotion/react"; import { useTranslation } from "react-i18next"; -import { normalizeUrl } from "../../../Utils/url"; import { useCreateMonitor, useDeleteMonitor, @@ -107,6 +106,10 @@ const CreateInfrastructureMonitor = () => { return errorKey ? errors[errorKey] : null; }; + const pageSchema = infrastructureMonitorValidation.fork(["url"], (s) => + isCreate ? s.required() : s.optional() + ); + // Populate form fields if editing useEffect(() => { if (isCreate) { @@ -197,7 +200,7 @@ const CreateInfrastructureMonitor = () => { secret: infrastructureMonitor.secret, }; - const { error } = infrastructureMonitorValidation.validate(form, { + const { error } = pageSchema.validate(form, { abortEarly: false, }); @@ -235,7 +238,7 @@ const CreateInfrastructureMonitor = () => { form = { ...(isCreate ? {} : { _id: monitorId }), ...rest, - url: normalizeUrl(infrastructureMonitor.url, https), + url: `http${https ? "s" : ""}://` + infrastructureMonitor.url, description: form.name, type: "hardware", notifications: infrastructureMonitor.notifications, @@ -253,20 +256,24 @@ const CreateInfrastructureMonitor = () => { }; const onChange = (event) => { - const { value, name } = event.target; - setInfrastructureMonitor({ - ...infrastructureMonitor, - [name]: value, - }); + const { name, value } = event.target; + + setInfrastructureMonitor((prev) => ({ ...prev, [name]: value })); + + if (name === "url") { + const candidate = value ? `http${https ? "s" : ""}://` + value : value; + + const urlSchema = pageSchema.extract("url"); + const { error } = urlSchema.validate(candidate, { abortEarly: false }); + + setErrors((prev) => ({ + ...prev, + url: error ? error.details[0].message : undefined, + })); + return; + } - const { error } = infrastructureMonitorValidation.validate( - { [name]: value }, - { abortEarly: false } - ); - setErrors((prev) => ({ - ...prev, - ...(error ? { [name]: error.details[0].message } : { [name]: undefined }), - })); + // leave other fields exactly as they were (or no per-field validation if that’s your current behavior) }; const handleCheckboxChange = (event) => { diff --git a/client/src/Utils/url.js b/client/src/Utils/url.js deleted file mode 100644 index 4fd402313..000000000 --- a/client/src/Utils/url.js +++ /dev/null @@ -1,5 +0,0 @@ -export const normalizeUrl = (input, useHttps) => { - const raw = String(input ?? "").trim(); - const cleaned = raw.replace(/^(?:https?:)?\/\//i, ""); - return `http${useHttps ? "s" : ""}://${cleaned}`; -}; diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 9c6699d4b..1de170406 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -367,20 +367,27 @@ const infrastructureMonitorValidation = joi.object({ .string() .trim() .custom((value, helpers) => { - const urlRegex = - /^(https?:\/\/)?(([0-9]{1,3}\.){3}[0-9]{1,3}|[\da-z\.-]+)(\.[a-z\.]{2,6})?(:(\d+))?([\/\w \.-]*)*\/?$/i; - - if (!urlRegex.test(value)) { - return helpers.error("string.invalidUrl"); + if (!/^https?:\/\//i.test(value)) return helpers.error("string.uri"); + try { + const u = new URL(value); + const hasPath = u.pathname && u.pathname !== "/"; + const hasQuery = !!u.search; + const hasHash = !!u.hash; + if (hasPath || hasQuery || hasHash) { + return helpers.error("string.invalidUrl"); + } + return value; + } catch { + return helpers.error("string.uri"); } - - return value; }) .messages({ "string.empty": "This field is required.", - "string.uri": "The URL you provided is not valid.", - "string.invalidUrl": "Please enter a valid URL with optional port", + "string.uri": "Please enter a valid URL starting with http:// or https://", + "string.invalidUrl": + "Only hostname (optional port) is allowed — no path, query, or fragment.", }), + name: joi.string().trim().max(50).allow("").messages({ "string.max": "This field should not exceed the 50 characters limit.", }), diff --git a/server/src/validation/joi.js b/server/src/validation/joi.js index ab9778e30..5048c0118 100755 --- a/server/src/validation/joi.js +++ b/server/src/validation/joi.js @@ -155,7 +155,11 @@ const createMonitorBodyValidation = joi.object({ name: joi.string().required(), description: joi.string().required(), type: joi.string().required(), - url: joi.string().required(), + url: joi + .string() + .trim() + .uri({ scheme: ["http", "https"] }) + .required(), ignoreTlsErrors: joi.boolean().default(false), port: joi.number(), isActive: joi.boolean(), From 94d171c25629aff6103452bb1228b1be6c151427 Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Sat, 9 Aug 2025 17:30:59 +0100 Subject: [PATCH 6/9] Align URL validation across frontend & backend to enforce host-only format --- .../src/Pages/Infrastructure/Create/index.jsx | 2 -- client/src/Validation/validation.js | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx index 9ded4e10f..df58f2d81 100644 --- a/client/src/Pages/Infrastructure/Create/index.jsx +++ b/client/src/Pages/Infrastructure/Create/index.jsx @@ -272,8 +272,6 @@ const CreateInfrastructureMonitor = () => { })); return; } - - // leave other fields exactly as they were (or no per-field validation if that’s your current behavior) }; const handleCheckboxChange = (event) => { diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 0f5aa2929..cb5b91ebf 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -378,12 +378,21 @@ const infrastructureMonitorValidation = joi.object({ if (!/^https?:\/\//i.test(value)) return helpers.error("string.uri"); try { const u = new URL(value); - const hasPath = u.pathname && u.pathname !== "/"; - const hasQuery = !!u.search; - const hasHash = !!u.hash; - if (hasPath || hasQuery || hasHash) { + // Host-only constraints + const hasCreds = u.username || u.password; + const invalidPath = u.pathname !== "/"; + const hasQuery = u.search !== ""; + const hasHash = u.hash !== ""; + if (hasCreds || invalidPath || hasQuery || hasHash) { return helpers.error("string.invalidUrl"); } + + if (u.port) { + const portNum = Number(u.port); + if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) { + return helpers.error("string.invalidUrl"); + } + } return value; } catch { return helpers.error("string.uri"); @@ -393,7 +402,7 @@ const infrastructureMonitorValidation = joi.object({ "string.empty": "This field is required.", "string.uri": "Please enter a valid URL starting with http:// or https://", "string.invalidUrl": - "Only hostname (optional port) is allowed — no path, query, or fragment.", + "Only hostname (optional port 1–65535) is allowed — no path, query, fragment, or credentials.", }), name: joi.string().trim().max(50).allow("").messages({ From 4da2ebe082fa3cc698d72d35d800c872227766aa Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Sat, 9 Aug 2025 17:46:52 +0100 Subject: [PATCH 7/9] Allow URL paths in monitor validation; --- client/src/Validation/validation.js | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index cb5b91ebf..72210695d 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -184,12 +184,12 @@ const monitorValidation = joi.object({ .min(1) .max(65535) .when("type", { - is: joi.valid("port", "game"), - then: joi.required().messages({ + is: "port", + then: joi.number().messages({ "number.base": "Port must be a number.", "number.min": "Port must be at least 1.", "number.max": "Port must be at most 65535.", - "any.required": "Port is required for port and game monitors.", + "any.required": "Port is required for port monitors.", }), otherwise: joi.optional(), }), @@ -205,14 +205,6 @@ const monitorValidation = joi.object({ expectedValue: joi.string().allow(null, ""), jsonPath: joi.string().allow(null, ""), matchMethod: joi.string().allow(null, ""), - gameId: joi.when("type", { - is: "game", - then: joi.string().required().messages({ - "string.empty": "Game selection is required for game monitors.", - "any.required": "Game selection is required for game monitors.", - }), - otherwise: joi.string().allow(null, ""), - }), }); const imageValidation = joi.object({ @@ -378,21 +370,21 @@ const infrastructureMonitorValidation = joi.object({ if (!/^https?:\/\//i.test(value)) return helpers.error("string.uri"); try { const u = new URL(value); - // Host-only constraints - const hasCreds = u.username || u.password; - const invalidPath = u.pathname !== "/"; - const hasQuery = u.search !== ""; - const hasHash = u.hash !== ""; - if (hasCreds || invalidPath || hasQuery || hasHash) { + + // Disallow credentials like http://user:pass@host + if (u.username || u.password) { return helpers.error("string.invalidUrl"); } + // Enforce valid port range when present if (u.port) { const portNum = Number(u.port); if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) { return helpers.error("string.invalidUrl"); } } + + //Paths, query, and fragments are now allowed return value; } catch { return helpers.error("string.uri"); @@ -401,8 +393,7 @@ const infrastructureMonitorValidation = joi.object({ .messages({ "string.empty": "This field is required.", "string.uri": "Please enter a valid URL starting with http:// or https://", - "string.invalidUrl": - "Only hostname (optional port 1–65535) is allowed — no path, query, fragment, or credentials.", + "string.invalidUrl": "Invalid URL (credentials not allowed; port must be 1–65535).", }), name: joi.string().trim().max(50).allow("").messages({ From 4fec3742e67b1f498bd208e7b1c90a3dbb801e35 Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Tue, 12 Aug 2025 07:32:47 +0100 Subject: [PATCH 8/9] Revert unintended validation.js changes to match upstream develop --- .../src/Pages/Infrastructure/Create/index.jsx | 31 ++++++------- client/src/Validation/validation.js | 45 ++++++++----------- 2 files changed, 35 insertions(+), 41 deletions(-) diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx index df58f2d81..0850b41de 100644 --- a/client/src/Pages/Infrastructure/Create/index.jsx +++ b/client/src/Pages/Infrastructure/Create/index.jsx @@ -256,22 +256,23 @@ const CreateInfrastructureMonitor = () => { }; const onChange = (event) => { - const { name, value } = event.target; - - setInfrastructureMonitor((prev) => ({ ...prev, [name]: value })); - - if (name === "url") { - const candidate = value ? `http${https ? "s" : ""}://` + value : value; - - const urlSchema = pageSchema.extract("url"); - const { error } = urlSchema.validate(candidate, { abortEarly: false }); + const { value, name } = event.target; + setInfrastructureMonitor({ + ...infrastructureMonitor, + [name]: value, + }); - setErrors((prev) => ({ - ...prev, - url: error ? error.details[0].message : undefined, - })); - return; - } + const adjustedValue = + name === "url" ? (value ? `http${https ? "s" : ""}://${value}` : value) : value; + + const { error } = infrastructureMonitorValidation.validate( + { [name]: adjustedValue }, + { abortEarly: false } + ); + setErrors((prev) => ({ + ...prev, + ...(error ? { [name]: error.details[0].message } : { [name]: undefined }), + })); }; const handleCheckboxChange = (event) => { diff --git a/client/src/Validation/validation.js b/client/src/Validation/validation.js index 72210695d..de248f87b 100644 --- a/client/src/Validation/validation.js +++ b/client/src/Validation/validation.js @@ -184,12 +184,12 @@ const monitorValidation = joi.object({ .min(1) .max(65535) .when("type", { - is: "port", - then: joi.number().messages({ + is: joi.valid("port", "game"), + then: joi.required().messages({ "number.base": "Port must be a number.", "number.min": "Port must be at least 1.", "number.max": "Port must be at most 65535.", - "any.required": "Port is required for port monitors.", + "any.required": "Port is required for port and game monitors.", }), otherwise: joi.optional(), }), @@ -205,6 +205,14 @@ const monitorValidation = joi.object({ expectedValue: joi.string().allow(null, ""), jsonPath: joi.string().allow(null, ""), matchMethod: joi.string().allow(null, ""), + gameId: joi.when("type", { + is: "game", + then: joi.string().required().messages({ + "string.empty": "Game selection is required for game monitors.", + "any.required": "Game selection is required for game monitors.", + }), + otherwise: joi.string().allow(null, ""), + }), }); const imageValidation = joi.object({ @@ -367,35 +375,20 @@ const infrastructureMonitorValidation = joi.object({ .string() .trim() .custom((value, helpers) => { - if (!/^https?:\/\//i.test(value)) return helpers.error("string.uri"); - try { - const u = new URL(value); - - // Disallow credentials like http://user:pass@host - if (u.username || u.password) { - return helpers.error("string.invalidUrl"); - } + const urlRegex = + /^(https?:\/\/)?(([0-9]{1,3}\.){3}[0-9]{1,3}|[\da-z\.-]+)(\.[a-z\.]{2,6})?(:(\d+))?([\/\w \.-]*)*\/?$/i; - // Enforce valid port range when present - if (u.port) { - const portNum = Number(u.port); - if (!Number.isInteger(portNum) || portNum < 1 || portNum > 65535) { - return helpers.error("string.invalidUrl"); - } - } - - //Paths, query, and fragments are now allowed - return value; - } catch { - return helpers.error("string.uri"); + if (!urlRegex.test(value)) { + return helpers.error("string.invalidUrl"); } + + return value; }) .messages({ "string.empty": "This field is required.", - "string.uri": "Please enter a valid URL starting with http:// or https://", - "string.invalidUrl": "Invalid URL (credentials not allowed; port must be 1–65535).", + "string.uri": "The URL you provided is not valid.", + "string.invalidUrl": "Please enter a valid URL with optional port", }), - name: joi.string().trim().max(50).allow("").messages({ "string.max": "This field should not exceed the 50 characters limit.", }), From 6e3c8b889d10af4ddd51b9cfbb69484b259d2c41 Mon Sep 17 00:00:00 2001 From: Yasir Rafique Date: Thu, 14 Aug 2025 11:12:02 +0100 Subject: [PATCH 9/9] refactor: simplify URL adjustment logic in onChange handler for readability --- client/src/Pages/Infrastructure/Create/index.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/src/Pages/Infrastructure/Create/index.jsx b/client/src/Pages/Infrastructure/Create/index.jsx index 0850b41de..58de2307d 100644 --- a/client/src/Pages/Infrastructure/Create/index.jsx +++ b/client/src/Pages/Infrastructure/Create/index.jsx @@ -262,8 +262,11 @@ const CreateInfrastructureMonitor = () => { [name]: value, }); - const adjustedValue = - name === "url" ? (value ? `http${https ? "s" : ""}://${value}` : value) : value; + let adjustedValue = value; + + if (name === "url" && value) { + adjustedValue = `http${https ? "s" : ""}://${value}`; + } const { error } = infrastructureMonitorValidation.validate( { [name]: adjustedValue },