diff --git a/client/src/Pages/Uptime/Configure/index.css b/client/src/Pages/Uptime/Configure/index.css
deleted file mode 100644
index 3f24bd011..000000000
--- a/client/src/Pages/Uptime/Configure/index.css
+++ /dev/null
@@ -1,11 +0,0 @@
-.configure-monitor button.MuiButtonBase-root {
- height: var(--env-var-height-2);
-}
-
-.configure-monitor .MuiStack-root:has(span.MuiTypography-root.input-error) {
- position: relative;
-}
-.configure-monitor span.MuiTypography-root.input-error {
- position: absolute;
- top: 100%;
-}
diff --git a/client/src/Pages/Uptime/Configure/index.jsx b/client/src/Pages/Uptime/Configure/index.jsx
deleted file mode 100644
index 061db6ac0..000000000
--- a/client/src/Pages/Uptime/Configure/index.jsx
+++ /dev/null
@@ -1,526 +0,0 @@
-// Components
-import Box from "@mui/material/Box";
-import Stack from "@mui/material/Stack";
-import Tooltip from "@mui/material/Tooltip";
-import Typography from "@mui/material/Typography";
-import Button from "@mui/material/Button";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Switch from "@mui/material/Switch";
-import ConfigBox from "../../../Components/ConfigBox";
-import Breadcrumbs from "../../../Components/Breadcrumbs";
-import TextInput from "../../../Components/Inputs/TextInput";
-import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
-import Select from "../../../Components/Inputs/Select";
-import Dialog from "../../../Components/Dialog";
-import PulseDot from "../../../Components/Animated/PulseDot";
-import Checkbox from "../../../Components/Inputs/Checkbox";
-
-// Utils
-import { useParams } from "react-router";
-import { useTheme } from "@emotion/react";
-import { useState } from "react";
-import { monitorValidation } from "../../../Validation/validation";
-import { createToast } from "../../../Utils/toastUtils";
-import { useTranslation } from "react-i18next";
-import PauseOutlinedIcon from "@mui/icons-material/PauseOutlined";
-import PlayArrowOutlinedIcon from "@mui/icons-material/PlayArrowOutlined";
-import { useMonitorUtils } from "../../../Hooks/useMonitorUtils";
-import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
-import {
- useDeleteMonitor,
- useUpdateMonitor,
- usePauseMonitor,
- useFetchMonitorById,
-} from "../../../Hooks/monitorHooks";
-import NotificationsConfig from "../../../Components/NotificationConfig";
-
-/**
- * Parses a URL string and returns a URL object.
- *
- * @param {string} url - The URL string to parse.
- * @returns {URL} - The parsed URL object if valid, otherwise an empty string.
- */
-const parseUrl = (url) => {
- try {
- return new URL(url);
- } catch (error) {
- return null;
- }
-};
-
-/**
- * Configure page displays monitor configurations and allows for editing actions.
- * @component
- */
-const Configure = () => {
- const { monitorId } = useParams();
-
- // Local state
- const [form, setForm] = useState({
- ignoreTlsErrors: false,
- interval: 60000,
- matchMethod: "equal",
- expectedValue: "",
- jsonPath: "",
- notifications: [],
- port: "",
- type: "http",
- });
- const [useAdvancedMatching, setUseAdvancedMatching] = useState(false);
- const [updateTrigger, setUpdateTrigger] = useState(false);
- const [isOpen, setIsOpen] = useState(false);
- const [errors, setErrors] = useState({});
-
- const triggerUpdate = () => {
- setUpdateTrigger(!updateTrigger);
- };
-
- // Network
- const [notifications, notificationsAreLoading, notificationsError] =
- useGetNotificationsByTeamId();
- const [pauseMonitor, isPausing, pauseError] = usePauseMonitor({});
- const [deleteMonitor, isDeleting] = useDeleteMonitor();
- const [updateMonitor, isUpdating] = useUpdateMonitor();
- const [isLoading] = useFetchMonitorById({
- monitorId,
- setMonitor: setForm,
- updateTrigger,
- });
-
- const MS_PER_MINUTE = 60000;
- const theme = useTheme();
-
- const matchMethodOptions = [
- { _id: "equal", name: "Equal" },
- { _id: "include", name: "Include" },
- { _id: "regex", name: "Regex" },
- ];
-
- const frequencies = [
- { _id: 1, name: "1 minute" },
- { _id: 2, name: "2 minutes" },
- { _id: 3, name: "3 minutes" },
- { _id: 4, name: "4 minutes" },
- { _id: 5, name: "5 minutes" },
- ];
-
- const expectedValuePlaceholders = {
- regex: "^(success|ok)$",
- equal: "success",
- include: "ok",
- };
-
- // Handlers
- const handlePause = async () => {
- const res = await pauseMonitor({ monitorId: form?._id, triggerUpdate });
- if (typeof res !== "undefined") {
- triggerUpdate();
- }
- };
-
- const handleRemove = async (event) => {
- event.preventDefault();
- await deleteMonitor({ monitor: form, redirect: "/uptime" });
- };
-
- const onChange = (event) => {
- let { name, value, checked } = event.target;
-
- if (name === "ignoreTlsErrors") {
- value = checked;
- }
-
- if (name === "useAdvancedMatching") {
- setForm((prevForm) => {
- return {
- ...prevForm,
- matchMethod: "equal",
- };
- });
- setUseAdvancedMatching(!useAdvancedMatching);
- return;
- }
-
- if (name === "interval") {
- value = value * MS_PER_MINUTE;
- }
- setForm({ ...form, [name]: value });
-
- const validation = monitorValidation.validate(
- { [name]: value },
- { abortEarly: false }
- );
-
- setErrors((prev) => {
- const updatedErrors = { ...prev };
- if (validation.error) updatedErrors[name] = validation.error.details[0].message;
- else delete updatedErrors[name];
- return updatedErrors;
- });
- };
-
- const onSubmit = async (e) => {
- e.preventDefault();
-
- const toSubmit = {
- _id: form?._id,
- url: form?.url,
- name: form?.name,
- type: form?.type,
- matchMethod: form?.matchMethod,
- expectedValue: form?.expectedValue,
- jsonPath: form?.jsonPath,
- interval: form?.interval,
- teamId: form?.teamId,
- userId: form?.userId,
- port: form?.port,
- ignoreTlsErrors: form?.ignoreTlsErrors,
- };
-
- if (!useAdvancedMatching) {
- toSubmit.matchMethod = "";
- toSubmit.expectedValue = "";
- toSubmit.jsonPath = "";
- }
-
- const validation = monitorValidation.validate(toSubmit, {
- abortEarly: false,
- });
-
- if (validation.error) {
- const newErrors = {};
- validation.error.details.forEach((err) => {
- newErrors[err.path[0]] = err.message;
- });
- setErrors(newErrors);
- createToast({ body: "Please check the form for errors." });
- return;
- }
-
- toSubmit.notifications = form?.notifications;
- await updateMonitor({ monitor: toSubmit, redirect: "/uptime" });
- };
-
- // Parse the URL
- const parsedUrl = parseUrl(form?.url);
- const protocol = parsedUrl?.protocol?.replace(":", "") || "";
-
- const { determineState, statusColor } = useMonitorUtils();
-
- const { t } = useTranslation();
-
- return (
-
-
-
-
-
-
- {form?.name}
-
-
-
-
-
-
-
-
- {form?.url?.replace(/^https?:\/\//, "") || "..."}
-
-
- {t("editing")}
-
-
-
-
- :
- }
- onClick={handlePause}
- >
- {form?.isActive ? t("pause") : t("resume")}
-
-
-
-
-
-
-
- {t("settingsGeneralSettings")}
-
- {t("distributedUptimeCreateSelectURL")}
-
-
-
- }
- id="monitor-url"
- label={t("urlMonitor")}
- placeholder="google.com"
- value={parsedUrl?.host || form?.url || ""}
- disabled={true}
- />
-
-
-
-
-
-
- {t("notificationConfig.title")}
- {t("notificationConfig.description")}
-
-
-
-
-
-
- {t("ignoreTLSError")}
-
- {t("ignoreTLSErrorDescription")}
-
-
-
- }
- label={t("tlsErrorIgnored")}
- />
-
-
-
-
-
- {t("distributedUptimeCreateAdvancedSettings")}
-
-
-
-
-
- {form?.type === "http" && useAdvancedMatching && (
- <>
-
-
-
-
- {t("uptimeCreate")}
-
-
-
-
-
- {t("uptimeCreateJsonPath")}
-
- jmespath.org
-
- {t("uptimeCreateJsonPathQuery")}
-
-
- >
- )}
-
-
-
-
-
-
-
- );
-};
-
-export default Configure;
diff --git a/client/src/Pages/Uptime/Create/index.jsx b/client/src/Pages/Uptime/Create/index.jsx
index 2416d2120..2d918cb9f 100644
--- a/client/src/Pages/Uptime/Create/index.jsx
+++ b/client/src/Pages/Uptime/Create/index.jsx
@@ -1,4 +1,14 @@
//Components
+import {
+ Box,
+ Button,
+ ButtonGroup,
+ FormControlLabel,
+ Stack,
+ Switch,
+ Tooltip,
+ Typography,
+} from "@mui/material";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import TextInput from "../../../Components/Inputs/TextInput";
import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
@@ -6,132 +16,186 @@ import Radio from "../../../Components/Inputs/Radio";
import Select from "../../../Components/Inputs/Select";
import ConfigBox from "../../../Components/ConfigBox";
import NotificationsConfig from "../../../Components/NotificationConfig";
-import Button from "@mui/material/Button";
-import ButtonGroup from "@mui/material/ButtonGroup";
-import Box from "@mui/material/Box";
-import Stack from "@mui/material/Stack";
-import Typography from "@mui/material/Typography";
-import Switch from "@mui/material/Switch";
-import FormControlLabel from "@mui/material/FormControlLabel";
import Checkbox from "../../../Components/Inputs/Checkbox";
+import Dialog from "../../../Components/Dialog";
+import PulseDot from "../../../Components/Animated/PulseDot";
+import SkeletonLayout from "./skeleton";
// Utils
+import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { monitorValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
+import {
+ PauseOutlined as PauseOutlinedIcon,
+ PlayArrowOutlined as PlayArrowOutlinedIcon,
+} from "@mui/icons-material";
+import { useMonitorUtils } from "../../../Hooks/useMonitorUtils";
import { useGetNotificationsByTeamId } from "../../../Hooks/useNotifications";
-import { useCreateMonitor, useFetchMonitorById } from "../../../Hooks/monitorHooks";
import { useParams } from "react-router-dom";
+import {
+ useCreateMonitor,
+ useDeleteMonitor,
+ useUpdateMonitor,
+ usePauseMonitor,
+ useFetchMonitorById,
+} from "../../../Hooks/monitorHooks";
-const CreateMonitor = () => {
- // Local state
- const [errors, setErrors] = useState({});
- const [https, setHttps] = useState(true);
- const [useAdvancedMatching, setUseAdvancedMatching] = useState(false);
+/**
+ * Parses a URL string and returns a URL object.
+ *
+ * @param {string} url - The URL string to parse.
+ * @returns {URL} - The parsed URL object if valid, otherwise an empty string.
+ */
+const parseUrl = (url) => {
+ try {
+ return new URL(url);
+ } catch (error) {
+ return null;
+ }
+};
+
+/**
+ * Create page renders monitor creation or configuration views.
+ * @component
+ */
+const UptimeCreate = ({ isClone = false }) => {
+ const { monitorId } = useParams();
+ const isCreate = typeof monitorId === "undefined" || isClone;
+
+ // States
const [monitor, setMonitor] = useState({
- url: "",
- name: "",
type: "http",
matchMethod: "equal",
expectedValue: "",
jsonPath: "",
notifications: [],
- interval: 1,
+ interval: 60000,
ignoreTlsErrors: false,
+ ...(isCreate ? { url: "", name: "" } : { port: undefined }),
});
-
- // Setup
- const MS_PER_MINUTE = 60000;
- const theme = useTheme();
- const { t } = useTranslation();
- const [notifications, notificationsAreLoading, error] = useGetNotificationsByTeamId();
- const [createMonitor, isCreating] = useCreateMonitor();
- const { monitorId } = useParams();
-
- const formatAndSet = (monitor) => {
- monitor.interval = monitor.interval / MS_PER_MINUTE;
- setMonitor(monitor);
+ const [errors, setErrors] = useState({});
+ const [https, setHttps] = useState(true);
+ const [isOpen, setIsOpen] = useState(false);
+ const [useAdvancedMatching, setUseAdvancedMatching] = useState(false);
+ const [updateTrigger, setUpdateTrigger] = useState(false);
+ const triggerUpdate = () => {
+ setUpdateTrigger(!updateTrigger);
};
+
+ // Hooks
+ const [notifications, notificationsAreLoading, notificationsError] =
+ useGetNotificationsByTeamId();
+ const { determineState, statusColor } = useMonitorUtils();
+ // Network
const [isLoading] = useFetchMonitorById({
monitorId,
- setMonitor: formatAndSet,
+ setMonitor,
updateTrigger: true,
});
+ const [createMonitor, isCreating] = useCreateMonitor();
+ const [pauseMonitor, isPausing] = usePauseMonitor({});
+ const [deleteMonitor, isDeleting] = useDeleteMonitor();
+ const [updateMonitor, isUpdating] = useUpdateMonitor();
- const SELECT_VALUES = [
- { _id: 1, name: "1 minute" },
- { _id: 2, name: "2 minutes" },
- { _id: 3, name: "3 minutes" },
- { _id: 4, name: "4 minutes" },
- { _id: 5, name: "5 minutes" },
+ // Setup
+ const theme = useTheme();
+ const { t } = useTranslation();
+
+ // Constants
+ const MS_PER_MINUTE = 60000;
+ const FREQUENCIES = [
+ { _id: 1, name: t("time.oneMinute") },
+ { _id: 2, name: t("time.twoMinutes") },
+ { _id: 3, name: t("time.threeMinutes") },
+ { _id: 4, name: t("time.fourMinutes") },
+ { _id: 5, name: t("time.fiveMinutes") },
+ ];
+ const CRUMBS = [
+ { name: "uptime", path: "/uptime" },
+ ...(isCreate
+ ? [{ name: "create", path: `/uptime/create` }]
+ : [
+ { name: "details", path: `/uptime/${monitorId}` },
+ { name: "configure", path: `/uptime/configure/${monitorId}` },
+ ]),
];
-
const matchMethodOptions = [
- { _id: "equal", name: "Equal" },
- { _id: "include", name: "Include" },
- { _id: "regex", name: "Regex" },
+ { _id: "equal", name: t("matchMethodOptions.equal") },
+ { _id: "include", name: t("matchMethodOptions.include") },
+ { _id: "regex", name: t("matchMethodOptions.regex") },
];
-
const expectedValuePlaceholders = {
- regex: "^(success|ok)$",
- equal: "success",
- include: "ok",
+ regex: t("matchMethodOptions.regexPlaceholder"),
+ equal: t("matchMethodOptions.equalPlaceholder"),
+ include: t("matchMethodOptions.includePlaceholder"),
};
-
const monitorTypeMaps = {
http: {
- label: "URL to monitor",
- placeholder: "google.com",
- namePlaceholder: "Google",
+ label: t("monitorType.http.label"),
+ placeholder: t("monitorType.http.placeholder"),
+ namePlaceholder: t("monitorType.http.namePlaceholder"),
},
ping: {
- label: "IP address to monitor",
- placeholder: "1.1.1.1",
- namePlaceholder: "Google",
+ label: t("monitorType.ping.label"),
+ placeholder: t("monitorType.ping.placeholder"),
+ namePlaceholder: t("monitorType.ping.namePlaceholder"),
},
docker: {
- label: "Container ID",
- placeholder: "abc123",
- namePlaceholder: "My Container",
+ label: t("monitorType.docker.label"),
+ placeholder: t("monitorType.docker.placeholder"),
+ namePlaceholder: t("monitorType.docker.namePlaceholder"),
},
port: {
- label: "URL to monitor",
- placeholder: "localhost",
- namePlaceholder: "Localhost:5173",
+ label: t("monitorType.port.label"),
+ placeholder: t("monitorType.port.placeholder"),
+ namePlaceholder: t("monitorType.port.namePlaceholder"),
},
};
- const BREADCRUMBS = [
- { name: "uptime", path: "/uptime" },
- { name: "create", path: `/uptime/create` },
- ];
-
// Handlers
-
const onSubmit = async (event) => {
event.preventDefault();
const { notifications, ...rest } = monitor;
- let form = {
- ...rest,
- url:
- //prepending protocol for url
- monitor.type === "http"
- ? `http${https ? "s" : ""}://` + monitor.url
- : monitor.url,
- port: monitor.type === "port" ? monitor.port : undefined,
- name: monitor.name || monitor.url.substring(0, 50),
- type: monitor.type,
- interval: monitor.interval * MS_PER_MINUTE,
- };
-
- // If not using advanced matching, remove advanced settings
+ let form = {};
+ if (isCreate) {
+ form = {
+ url:
+ monitor.type === "http" && !isClone
+ ? `http${https ? "s" : ""}://` + monitor.url
+ : monitor.url,
+ name: monitor.name || monitor.url.substring(0, 50),
+ type: monitor.type,
+ port: monitor.type === "port" ? monitor.port : undefined,
+ interval: monitor.interval,
+ matchMethod: monitor.matchMethod,
+ expectedValue: monitor.expectedValue,
+ jsonPath: monitor.jsonPath,
+ ignoreTlsErrors: monitor.ignoreTlsErrors,
+ };
+ } else {
+ form = {
+ _id: monitor._id,
+ url: monitor.url,
+ name: monitor.name || monitor.url.substring(0, 50),
+ type: monitor.type,
+ matchMethod: monitor.matchMethod,
+ expectedValue: monitor.expectedValue,
+ jsonPath: monitor.jsonPath,
+ interval: monitor.interval,
+ teamId: monitor.teamId,
+ userId: monitor.userId,
+ port: monitor.type === "port" ? monitor.port : undefined,
+ ignoreTlsErrors: monitor.ignoreTlsErrors,
+ };
+ }
if (!useAdvancedMatching) {
- form.matchMethod = undefined;
- form.expectedValue = undefined;
- form.jsonPath = undefined;
+ form.matchMethod = isCreate ? undefined : "";
+ form.expectedValue = isCreate ? undefined : "";
+ form.jsonPath = isCreate ? undefined : "";
}
const { error } = monitorValidation.validate(form, {
@@ -144,7 +208,7 @@ const CreateMonitor = () => {
newErrors[err.path[0]] = err.message;
});
setErrors(newErrors);
- createToast({ body: "Please check the form for errors." });
+ createToast({ body: t("checkFormError") });
return;
}
@@ -154,15 +218,18 @@ const CreateMonitor = () => {
notifications: monitor.notifications,
};
- await createMonitor({ monitor: form, redirect: "/uptime" });
+ if (isCreate) {
+ await createMonitor({ monitor: form, redirect: "/uptime" });
+ } else {
+ await updateMonitor({ monitor: form, redirect: "/uptime" });
+ }
};
const onChange = (event) => {
- const { name, value, checked } = event.target;
+ let { name, value, checked } = event.target;
- let newValue = value;
if (name === "ignoreTlsErrors") {
- newValue = checked;
+ value = checked;
}
if (name === "useAdvancedMatching") {
@@ -170,15 +237,14 @@ const CreateMonitor = () => {
return;
}
- const updatedMonitor = {
- ...monitor,
- [name]: newValue,
- };
+ if (name === "interval") {
+ value = value * MS_PER_MINUTE;
+ }
- setMonitor(updatedMonitor);
+ setMonitor((prev) => ({ ...prev, [name]: value }));
const { error } = monitorValidation.validate(
- { type: monitor.type, [name]: newValue },
+ { type: monitor.type, [name]: value },
{ abortEarly: false }
);
@@ -188,122 +254,254 @@ const CreateMonitor = () => {
}));
};
+ const handlePause = async () => {
+ await pauseMonitor({ monitorId, triggerUpdate });
+ };
+
+ const handleRemove = async (event) => {
+ event.preventDefault();
+ await deleteMonitor({ monitor, redirect: "/uptime" });
+ };
+
+ const isBusy = isLoading || isCreating || isDeleting || isUpdating || isPausing;
+ const displayInterval = monitor?.interval / MS_PER_MINUTE || 1;
+ const parsedUrl = parseUrl(monitor?.url);
+ const protocol = parsedUrl?.protocol?.replace(":", "") || "";
+
+ useEffect(() => {
+ if (!isCreate || isClone) {
+ if (monitor.matchMethod) {
+ setUseAdvancedMatching(true);
+ } else {
+ setUseAdvancedMatching(false);
+ }
+ }
+ }, [monitor, isCreate]);
+
+ if (Object.keys(monitor).length === 0) {
+ return ;
+ }
+
return (
-
+
-
-
- {t("createYour")}{" "}
-
-
- {t("monitor")}
-
-
-
+
- {t("distributedUptimeCreateChecks")}
-
-
- {t("distributedUptimeCreateChecksDescription")}
+
+ {!isCreate ? monitor.name : t("createYour") + " "}
+
+ {isCreate && (
+
+ {t("monitor")}
+
+ )}
+ {!isCreate && (
+
+
+
+
+
+
+
+ {monitor.url?.replace(/^https?:\/\//, "") || "..."}
+
+
+ {t("editing")}
+
+
+ )}
-
-
+ {!isCreate && (
+
+ :
+ }
+ onClick={handlePause}
+ >
+ {monitor?.isActive ? t("pause") : t("resume")}
+
+
+
+ )}
+
+ {isCreate && (
+
+
+
+ {t("distributedUptimeCreateChecks")}
+
+
+ {t("distributedUptimeCreateChecksDescription")}
+
+
+
+
+
+ {monitor.type === "http" ? (
+
+
+
+
+ ) : (
+ ""
+ )}
+
- {monitor.type === "http" ? (
-
-
-
-
+ {errors["type"]}
+
+
) : (
""
)}
-
-
-
- {errors["type"] ? (
-
-
- {errors["type"]}
-
-
- ) : (
- ""
- )}
-
-
+
+ )}
{
{t("settingsGeneralSettings")}
- {t(`uptimeGeneralInstructions.${monitor.type}`)}
+ {isCreate
+ ? t(`uptimeGeneralInstructions.${monitor.type}`)
+ : t("distributedUptimeCreateSelectURL")}
-
+
: null
+ type={monitor?.type === "http" ? "url" : "text"}
+ label={
+ (monitor.type === "http" || monitor.type === "port") && !isCreate
+ ? t("url")
+ : monitorTypeMaps[monitor.type].label || t("urlMonitor")
}
- label={monitorTypeMaps[monitor.type].label || "URL to monitor"}
- https={https}
placeholder={monitorTypeMaps[monitor.type].placeholder || ""}
- value={monitor.url}
- onChange={onChange}
- error={errors["url"] ? true : false}
+ value={parsedUrl?.host + parsedUrl?.pathname || monitor?.url || ""}
+ https={isCreate ? https : protocol === "https"}
+ startAdornment={
+ monitor?.type === "http" && (
+
+ )
+ }
helperText={errors["url"]}
+ onChange={onChange}
+ disabled={!isCreate}
/>
{
type="text"
label={t("displayName")}
isOptional={true}
- placeholder={monitorTypeMaps[monitor.type].namePlaceholder || ""}
- value={monitor.name}
+ placeholder={monitorTypeMaps[monitor.type].namePlaceholder}
+ value={monitor.name || ""}
onChange={onChange}
error={errors["name"] ? true : false}
helperText={errors["name"]}
@@ -368,6 +575,7 @@ const CreateMonitor = () => {
@@ -382,7 +590,7 @@ const CreateMonitor = () => {
{
{t("distributedUptimeCreateAdvancedSettings")}
-
+
-
+ {monitor.type === "http" && (
+
+ )}
{monitor.type === "http" && useAdvancedMatching && (
<>
{
{
color={theme.palette.primary.contrastTextTertiary}
opacity={0.8}
>
- {t("uptimeCreateJsonPath")}
+ {t("uptimeCreateJsonPath") + " "}
{
>
jmespath.org
- {t("uptimeCreateJsonPathQuery")}
+ {" " + t("uptimeCreateJsonPathQuery")}
>
@@ -491,14 +701,32 @@ const CreateMonitor = () => {
variant="contained"
color="accent"
disabled={!Object.values(errors).every((value) => value === undefined)}
- loading={isCreating}
+ loading={isBusy}
+ sx={{ px: theme.spacing(12) }}
>
- {t("createMonitor")}
+ {t("settingsSave")}
+
+ {!isCreate && (
+
);
};
-export default CreateMonitor;
+UptimeCreate.propTypes = {
+ isClone: PropTypes.bool,
+};
+
+export default UptimeCreate;
diff --git a/client/src/Pages/Uptime/Configure/skeleton.jsx b/client/src/Pages/Uptime/Create/skeleton.jsx
similarity index 100%
rename from client/src/Pages/Uptime/Configure/skeleton.jsx
rename to client/src/Pages/Uptime/Create/skeleton.jsx
diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx
index 6de07a2de..350d2f82d 100644
--- a/client/src/Routes/index.jsx
+++ b/client/src/Routes/index.jsx
@@ -14,7 +14,6 @@ import AuthNewPasswordConfirmed from "../Pages/Auth/NewPasswordConfirmed";
import Uptime from "../Pages/Uptime/Monitors";
import UptimeDetails from "../Pages/Uptime/Details";
import UptimeCreate from "../Pages/Uptime/Create";
-import UptimeConfigure from "../Pages/Uptime/Configure";
// PageSpeed
import PageSpeed from "../Pages/PageSpeed/Monitors";
@@ -81,16 +80,20 @@ const Routes = () => {
/>
}
/>
+ }
+ />
}
/>
}
+ element={}
/>