diff --git a/Client/src/App.jsx b/Client/src/App.jsx
index 62b6bd9ff..82c8203a8 100644
--- a/Client/src/App.jsx
+++ b/Client/src/App.jsx
@@ -41,7 +41,6 @@ import { logger } from "./Utils/Logger"; // Import the logger
import { networkService } from "./main";
import { Infrastructure } from "./Pages/Infrastructure";
import InfrastructureDetails from "./Pages/Infrastructure/Details";
-import Test from "./Pages/test";
function App() {
const AdminCheckedRegister = withAdminCheck(Register);
const MonitorsWithAdminProp = withAdminProp(Monitors);
@@ -90,11 +89,6 @@ function App() {
path="/"
element={}
>
- }
- />
-
const theme = useTheme();
const colors = {
success: theme.palette.success.main,
- error: theme.palette.error.contrastText,
+ error: theme.palette.error.main,
info: theme.palette.info.border,
};
-
return (
{
- const theme = useTheme();
-
- const [isVisible, setVisible] = useState(false);
-
- return (
-
- {label && (
-
- {label}
- {isRequired ? (
-
- *
-
- ) : (
- ""
- )}
- {isOptional ? (
-
- {optionalLabel || "(optional)"}
-
- ) : (
- ""
- )}
-
- )}
-
-
- {https ? "https" : "http"}://
-
-
- ),
- endAdornment: type === "password" && (
-
- setVisible((show) => !show)}
- sx={{
- color: theme.palette.border.dark,
- padding: theme.spacing(1),
- "&:focus-visible": {
- outline: `2px solid ${theme.palette.primary.main}`,
- outlineOffset: `2px`,
- },
- "& .MuiTouchRipple-root": {
- pointerEvents: "none",
- display: "none",
- },
- }}
- >
- {!isVisible ? : }
-
-
- ),
- }}
- />
- {error && (
-
- {error}
-
- )}
-
- );
- }
-);
-
-Field.displayName = "Field";
-
-Field.propTypes = {
- type: PropTypes.oneOf(["text", "password", "url", "email", "description", "number"]),
- id: PropTypes.string.isRequired,
- name: PropTypes.string,
- label: PropTypes.string,
- https: PropTypes.bool,
- isRequired: PropTypes.bool,
- isOptional: PropTypes.bool,
- optionalLabel: PropTypes.string,
- autoComplete: PropTypes.string,
- placeholder: PropTypes.string,
- value: PropTypes.string.isRequired,
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- onInput: PropTypes.func,
- error: PropTypes.string,
- disabled: PropTypes.bool,
- hidden: PropTypes.bool,
- className: PropTypes.string,
- hideErrorText: PropTypes.bool,
-};
-
-export default Field;
diff --git a/Client/src/Components/Inputs/TextInput/Adornments/index.jsx b/Client/src/Components/Inputs/TextInput/Adornments/index.jsx
index 0709b5425..686db183b 100644
--- a/Client/src/Components/Inputs/TextInput/Adornments/index.jsx
+++ b/Client/src/Components/Inputs/TextInput/Adornments/index.jsx
@@ -29,6 +29,10 @@ export const HttpAdornment = ({ https }) => {
);
};
+HttpAdornment.propTypes = {
+ https: PropTypes.bool.isRequired,
+};
+
export const PasswordEndAdornment = ({ fieldType, setFieldType }) => {
const theme = useTheme();
return (
@@ -55,6 +59,7 @@ export const PasswordEndAdornment = ({ fieldType, setFieldType }) => {
);
};
-HttpAdornment.propTypes = {
- https: PropTypes.bool.isRequired,
+PasswordEndAdornment.propTypes = {
+ fieldType: PropTypes.string,
+ setFieldType: PropTypes.func,
};
diff --git a/Client/src/Components/Inputs/TextInput/index.jsx b/Client/src/Components/Inputs/TextInput/index.jsx
index d97d1ebac..26f051c06 100644
--- a/Client/src/Components/Inputs/TextInput/index.jsx
+++ b/Client/src/Components/Inputs/TextInput/index.jsx
@@ -6,6 +6,11 @@ import PropTypes from "prop-types";
const getSx = (theme, type, maxWidth) => {
const sx = {
maxWidth: maxWidth,
+ "& .MuiFormHelperText-root": {
+ position: "absolute",
+ bottom: `-${theme.spacing(24)}`,
+ minHeight: theme.spacing(24),
+ },
};
if (type === "url") {
@@ -56,6 +61,8 @@ Optional.propTypes = {
const TextInput = forwardRef(
(
{
+ id,
+ name,
type,
value,
placeholder,
@@ -63,19 +70,34 @@ const TextInput = forwardRef(
isOptional,
optionalLabel,
onChange,
+ onBlur,
error = false,
helperText = null,
startAdornment = null,
endAdornment = null,
label = null,
maxWidth = "100%",
+ flex,
+ marginTop,
+ marginRight,
+ marginBottom,
+ marginLeft,
+ disabled = false,
+ hidden = false,
},
ref
) => {
const [fieldType, setFieldType] = useState(type);
const theme = useTheme();
return (
-
+
}
);
@@ -113,18 +139,28 @@ TextInput.displayName = "TextInput";
TextInput.propTypes = {
type: PropTypes.string,
+ id: PropTypes.string.isRequired,
+ name: PropTypes.string,
value: PropTypes.string,
placeholder: PropTypes.string,
isRequired: PropTypes.bool,
isOptional: PropTypes.bool,
optionalLabel: PropTypes.string,
onChange: PropTypes.func,
+ onBlur: PropTypes.func,
error: PropTypes.bool,
helperText: PropTypes.string,
startAdornment: PropTypes.node,
endAdornment: PropTypes.node,
label: PropTypes.string,
maxWidth: PropTypes.string,
+ flex: PropTypes.number,
+ marginTop: PropTypes.string,
+ marginRight: PropTypes.string,
+ marginBottom: PropTypes.string,
+ marginLeft: PropTypes.string,
+ disabled: PropTypes.bool,
+ hidden: PropTypes.bool,
};
export default TextInput;
diff --git a/Client/src/Components/TabPanels/Account/PasswordPanel.jsx b/Client/src/Components/TabPanels/Account/PasswordPanel.jsx
index 0ea313d6c..ae322156c 100644
--- a/Client/src/Components/TabPanels/Account/PasswordPanel.jsx
+++ b/Client/src/Components/TabPanels/Account/PasswordPanel.jsx
@@ -3,7 +3,8 @@ import { useState } from "react";
import { useTheme } from "@emotion/react";
import { Box, Stack, Typography } from "@mui/material";
import LoadingButton from "@mui/lab/LoadingButton";
-import Field from "../../Inputs/Field";
+import { PasswordEndAdornment } from "../../Inputs/TextInput/Adornments";
+import TextInput from "../../Inputs/TextInput";
import { credentials } from "../../../Validation/validation";
import Alert from "../../Alert";
import { update } from "../../../Features/Auth/authSlice";
@@ -113,7 +114,7 @@ const PasswordPanel = () => {
maxWidth={"80ch"}
marginInline={"auto"}
>
- {
>
Current password
- }
+ flex={1}
/>
{
New password
- }
+ flex={1}
/>
{
Confirm new password
- }
+ flex={1}
/>
{Object.keys(errors).length > 0 && (
diff --git a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx
index 0875891f5..9c00f6c02 100644
--- a/Client/src/Components/TabPanels/Account/ProfilePanel.jsx
+++ b/Client/src/Components/TabPanels/Account/ProfilePanel.jsx
@@ -3,7 +3,7 @@ import { useRef, useState } from "react";
import TabPanel from "@mui/lab/TabPanel";
import { Box, Button, Divider, Stack, Typography } from "@mui/material";
import Avatar from "../../Avatar";
-import Field from "../../Inputs/Field";
+import TextInput from "../../Inputs/TextInput";
import ImageField from "../../Inputs/Image";
import { credentials, imageValidation } from "../../../Validation/validation";
import { useDispatch, useSelector } from "react-redux";
@@ -229,26 +229,30 @@ const ProfilePanel = () => {
First name
-
Last name
-
@@ -261,14 +265,14 @@ const ProfilePanel = () => {
This is your current email address — it cannot be changed.
- logger.warn("disabled")}
- // error={errors[idToName["edit-email"]]}
disabled={true}
+ flex={1}
/>
diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx
index 7d9171384..74fae01c6 100644
--- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx
+++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx
@@ -2,7 +2,7 @@ import { useTheme } from "@emotion/react";
import TabPanel from "@mui/lab/TabPanel";
import { Button, ButtonGroup, Stack, Typography } from "@mui/material";
import { useEffect, useState } from "react";
-import Field from "../../Inputs/Field";
+import TextInput from "../../Inputs/TextInput";
import { credentials } from "../../../Validation/validation";
import { networkService } from "../../../main";
import { createToast } from "../../../Utils/toastUtils";
@@ -338,13 +338,15 @@ const TeamPanel = () => {
onClose={closeInviteModal}
theme={theme}
>
-
diff --git a/Client/src/Pages/Auth/ForgotPassword.jsx b/Client/src/Pages/Auth/ForgotPassword.jsx
index 675bd0239..1fd5f1b2f 100644
--- a/Client/src/Pages/Auth/ForgotPassword.jsx
+++ b/Client/src/Pages/Auth/ForgotPassword.jsx
@@ -7,7 +7,7 @@ import { useEffect, useState } from "react";
import { credentials } from "../../Validation/validation";
import { useNavigate } from "react-router-dom";
import { IconBox } from "./styled";
-import Field from "../../Components/Inputs/Field";
+import TextInput from "../../Components/Inputs/TextInput";
import Logo from "../../assets/icons/bwu-icon.svg?react";
import Key from "../../assets/icons/key.svg?react";
import Background from "../../assets/Images/background-grid.svg?react";
@@ -160,7 +160,7 @@ const ForgotPassword = () => {
spellCheck={false}
onSubmit={handleSubmit}
>
- {
placeholder="Enter your email"
value={form.email}
onChange={handleChange}
- error={errors.email}
+ error={errors.email ? true : false}
+ helperText={errors.email}
/>
{
display="grid"
gap={{ xs: theme.spacing(12), sm: theme.spacing(16) }}
>
- {
value={form.email}
onInput={(e) => (e.target.value = e.target.value.toLowerCase())}
onChange={onChange}
- error={errors.email}
+ error={errors.email ? true : false}
+ helperText={errors.email}
ref={inputRef}
/>
{
gap: { xs: theme.spacing(12), sm: theme.spacing(16) },
}}
>
- {
autoComplete="current-password"
value={form.password}
onChange={onChange}
- error={errors.password}
+ error={errors.password ? true : false}
+ helperText={errors.password}
ref={inputRef}
+ endAdornment={}
/>
-
-
-
-
- (e.target.value = e.target.value.toLowerCase())}
onChange={onChange}
- error={errors.email}
+ error={errors.email ? true : false}
+ helperText={errors.email}
ref={inputRef}
/>
{
spellCheck={false}
onSubmit={handleSubmit}
>
- {
placeholder="••••••••"
value={form.password}
onChange={handleChange}
- error={errors.password}
+ error={errors.password ? true : false}
+ helperText={errors.password}
+ endAdornment={}
/>
{
spellCheck={false}
onSubmit={handleSubmit}
>
- {
placeholder="••••••••"
value={form.confirm}
onChange={handleChange}
- error={errors.confirm}
+ error={errors.confirm ? true : false}
+ helperText={errors.confirm}
+ endAdornment={}
/>
-
+ />
+
{
event.preventDefault();
const { value, id } = event.target;
let name = appendedId ?? idMap[id] ?? id;
-
if (name.includes("notification-")) {
name = name.replace("notification-", "");
let hasNotif = infrastructureMonitor.notifications.some(
@@ -253,7 +251,7 @@ const CreateInfrastructureMonitor = () => {
- {
value={infrastructureMonitor.url}
onBlur={handleBlur}
onChange={handleChange}
- error={errors["url"]}
+ error={errors["url"] ? true : false}
+ helperText={errors["url"]}
/>
- {
onChange={handleChange}
error={errors["name"]}
/>
-
@@ -368,15 +368,6 @@ const CreateInfrastructureMonitor = () => {
onBlur={(e) => handleBlur(e, "interval")}
items={frequencies}
/>
- {/* */}
{
};
const handleSubmit = async () => {
- if (hasValidationErrors(form, maintenanceWindowValidation, setErrors))
- return;
+ if (hasValidationErrors(form, maintenanceWindowValidation, setErrors)) return;
// Build timestamp for maintenance window from startDate and startTime
const start = dayjs(form.startDate)
.set("hour", form.startTime.hour())
@@ -467,14 +466,15 @@ const CreateMaintenance = () => {
direction="row"
spacing={theme.spacing(8)}
>
- {
handleFormChange("duration", event.target.value);
}}
- error={errors["duration"]}
+ error={errors["duration"] ? true : false}
+ helperText={errors["duration"]}
/>
{
- {
handleFormChange("name", event.target.value);
}}
- error={errors["name"]}
+ error={errors["name"] ? true : false}
+ helperText={errors["name"]}
/>
diff --git a/Client/src/Pages/Monitors/Configure/index.jsx b/Client/src/Pages/Monitors/Configure/index.jsx
index 22cc8618e..ba23c5634 100644
--- a/Client/src/Pages/Monitors/Configure/index.jsx
+++ b/Client/src/Pages/Monitors/Configure/index.jsx
@@ -14,7 +14,8 @@ import {
getUptimeMonitorsByTeamId,
deleteUptimeMonitor,
} from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
-import Field from "../../../Components/Inputs/Field";
+import TextInput from "../../../Components/Inputs/TextInput";
+import { HttpAdornment } from "../../../Components/Inputs/TextInput/Adornments";
import PauseIcon from "../../../assets/icons/pause-icon.svg?react";
import ResumeIcon from "../../../assets/icons/resume-icon.svg?react";
import Select from "../../../Components/Inputs/Select";
@@ -343,17 +344,17 @@ const Configure = () => {
- }
id="monitor-url"
label="URL to monitor"
placeholder="google.com"
value={parsedUrl?.host || monitor?.url || ""}
disabled={true}
- error={errors["url"]}
/>
- {
placeholder="Google"
value={monitor?.name || ""}
onChange={handleChange}
- error={errors["name"]}
+ error={errors["name"] ? true : false}
+ helperText={errors["name"]}
/>
@@ -405,7 +407,7 @@ const Configure = () => {
(notification) => notification.type === "emails"
) ? (
- {
- }
label={monitorTypeMaps[monitor.type].label || "URL to monitor"}
https={https}
placeholder={monitorTypeMaps[monitor.type].placeholder || ""}
value={monitor.url}
onChange={handleChange}
- error={errors["url"]}
+ error={errors["url"] ? true : false}
+ helperText={errors["url"]}
/>
- {
placeholder={monitorTypeMaps[monitor.type].namePlaceholder || ""}
value={monitor.name}
onChange={handleChange}
- error={errors["name"]}
+ error={errors["name"] ? true : false}
+ helperText={errors["name"]}
/>
@@ -381,7 +385,7 @@ const CreateMonitor = () => {
(notification) => notification.type === "emails"
) ? (
- {
},
}}
>
-
- {
isOptional={true}
value={monitor?.name || ""}
onChange={handleChange}
- error={errors.name}
+ error={errors.name ? true : false}
+ helperText={errors.name}
/>
@@ -383,7 +385,7 @@ const PageSpeedConfigure = () => {
(notification) => notification.type === "emails"
) ? (
- {
- }
placeholder="google.com"
value={monitor.url}
onChange={handleChange}
- error={errors["url"]}
+ error={errors["url"] ? true : false}
+ helperText={errors["url"]}
/>
- {
placeholder="Google"
value={monitor.name}
onChange={handleChange}
- error={errors["name"]}
+ error={errors["name"] ? true : false}
+ helperText={errors["name"]}
/>
@@ -315,7 +318,7 @@ const CreatePageSpeed = () => {
(notification) => notification.type === "emails"
) ? (
- {
-
Clear all stats. This is irreversible.
diff --git a/Client/src/Pages/test.jsx b/Client/src/Pages/test.jsx
deleted file mode 100644
index 8f5bb464e..000000000
--- a/Client/src/Pages/test.jsx
+++ /dev/null
@@ -1,192 +0,0 @@
-import { Stack, Typography } from "@mui/material";
-import Field from "../Components/Inputs/Field";
-import TextInput from "../Components/Inputs/TextInput";
-import { useState, useEffect, useRef } from "react";
-import { HttpAdornment } from "../Components/Inputs/TextInput/Adornments";
-import { PasswordEndAdornment } from "../Components/Inputs/TextInput/Adornments";
-const Test = () => {
- const [originalValue, setOriginalValue] = useState("");
- const [originalError, setOriginalError] = useState("");
-
- const [newValue, setNewValue] = useState("");
- const [newError, setNewError] = useState("");
-
- const [thresholdValue, setThresholdValue] = useState(20);
- const [thresholdError, setThresholdError] = useState("");
-
- const [thresholdValue2, setThresholdValue2] = useState(20);
- const [thresholdError2, setThresholdError2] = useState("");
-
- const inputRef = useRef(null);
-
- useEffect(() => {
- if (inputRef.current) {
- inputRef.current.focus();
- }
- }, []);
-
- const checkError = (value) => {
- if (value !== "clear") {
- return "This is an error";
- }
- return "";
- };
-
- const checkThresholdError = (value) => {
- if (value !== 99) {
- return "This is a threshold error";
- }
- return "";
- };
- const checkThresholdError2 = (value) => {
- if (value !== 99) {
- return "This is a threshold error 2";
- }
- return "";
- };
-
- const handleOriginalValue = (e) => {
- setOriginalError(checkError(e.target.value));
- setOriginalValue(e.target.value);
- };
-
- const handleNewValue = (e) => {
- setNewError(checkError(e.target.value));
- setNewValue(e.target.value);
- };
-
- const handleThresholdValue = (e) => {
- const parsedVal = parseInt(e.target.value);
- setThresholdError(checkThresholdError(parsedVal));
- setThresholdValue(parsedVal);
- };
-
- const handleThresholdValue2 = (e) => {
- const parsedVal = parseInt(e.target.value);
- setThresholdError2(checkThresholdError2(parsedVal));
- setThresholdValue2(parsedVal);
- };
-
- return (
-
-
- This is a test page for the TextInput component. It is a rationalized Input
- component.
-
- Type anything for an error.
- Typing "clear" will clear the error for text based input
- Typing "99" will clear the error for threshold based input
-
-
-
-
- }
- onChange={handleNewValue}
- error={newError !== ""}
- helperText={newError}
- />
-
-
- }
- onChange={handleNewValue}
- error={newError !== ""}
- helperText={newError}
- ref={inputRef}
- />
-
-
-
-
-
- Short field for threshold. Easily show/hide error text
-
-
-
- {thresholdError} {thresholdError2}
-
-
- );
-};
-
-export default Test;