diff --git a/Client/package-lock.json b/Client/package-lock.json index 25f2601ef..658f28287 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -11,6 +11,7 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", + "@hello-pangea/dnd": "^17.0.0", "@mui/icons-material": "6.3.1", "@mui/lab": "6.0.0-beta.22", "@mui/material": "6.3.1", @@ -25,7 +26,6 @@ "jwt-decode": "^4.0.0", "mui-color-input": "^5.0.1", "react": "^18.2.0", - "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-redux": "9.2.0", "react-router": "^6.23.0", @@ -995,6 +995,24 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hello-pangea/dnd": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@hello-pangea/dnd/-/dnd-17.0.0.tgz", + "integrity": "sha512-LDDPOix/5N0j5QZxubiW9T0M0+1PR0rTDWeZF5pu1Tz91UQnuVK4qQ/EjY83Qm2QeX0eM8qDXANfDh3VVqtR4Q==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "css-box-model": "^1.2.1", + "memoize-one": "^6.0.0", + "raf-schd": "^4.0.3", + "react-redux": "^9.1.2", + "redux": "^5.0.1", + "use-memo-one": "^1.1.3" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -2370,15 +2388,6 @@ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "license": "MIT" }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", - "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", @@ -2411,25 +2420,6 @@ "@types/react": "^18.0.0" } }, - "node_modules/@types/react-redux": { - "version": "7.1.34", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.34.tgz", - "integrity": "sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==", - "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "node_modules/@types/react-redux/node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, "node_modules/@types/react-transition-group": { "version": "4.4.12", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", @@ -4978,9 +4968,9 @@ } }, "node_modules/memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" }, "node_modules/mime-db": { "version": "1.52.0", @@ -5477,62 +5467,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-beautiful-dnd": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz", - "integrity": "sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ==", - "deprecated": "react-beautiful-dnd is now deprecated. Context and options: https://github.com/atlassian/react-beautiful-dnd/issues/2672", - "dependencies": { - "@babel/runtime": "^7.9.2", - "css-box-model": "^1.2.0", - "memoize-one": "^5.1.1", - "raf-schd": "^4.0.2", - "react-redux": "^7.2.0", - "redux": "^4.0.4", - "use-memo-one": "^1.1.1" - }, - "peerDependencies": { - "react": "^16.8.5 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-beautiful-dnd/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/react-beautiful-dnd/node_modules/react-redux": { - "version": "7.2.9", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", - "integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==", - "dependencies": { - "@babel/runtime": "^7.15.4", - "@types/react-redux": "^7.1.20", - "hoist-non-react-statics": "^3.3.2", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-is": "^17.0.2" - }, - "peerDependencies": { - "react": "^16.8.3 || ^17 || ^18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/react-beautiful-dnd/node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", diff --git a/Client/package.json b/Client/package.json index 7f3d9cfe7..af0536d3f 100644 --- a/Client/package.json +++ b/Client/package.json @@ -14,6 +14,7 @@ "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", + "@hello-pangea/dnd": "^17.0.0", "@mui/icons-material": "6.3.1", "@mui/lab": "6.0.0-beta.22", "@mui/material": "6.3.1", @@ -28,7 +29,6 @@ "jwt-decode": "^4.0.0", "mui-color-input": "^5.0.1", "react": "^18.2.0", - "react-beautiful-dnd": "^13.1.1", "react-dom": "^18.2.0", "react-redux": "9.2.0", "react-router": "^6.23.0", diff --git a/Client/src/Components/Inputs/Checkbox/index.jsx b/Client/src/Components/Inputs/Checkbox/index.jsx index b5b5b8981..08bb5b9c4 100644 --- a/Client/src/Components/Inputs/Checkbox/index.jsx +++ b/Client/src/Components/Inputs/Checkbox/index.jsx @@ -115,7 +115,7 @@ Checkbox.propTypes = { label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, size: PropTypes.oneOf(["small", "medium", "large"]), isChecked: PropTypes.bool.isRequired, - value: PropTypes.string, + value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), onChange: PropTypes.func, isDisabled: PropTypes.bool, alignSelf: PropTypes.bool, diff --git a/Client/src/Components/Inputs/ColorPicker/index.jsx b/Client/src/Components/Inputs/ColorPicker/index.jsx index 52068e2c6..de63400bc 100644 --- a/Client/src/Components/Inputs/ColorPicker/index.jsx +++ b/Client/src/Components/Inputs/ColorPicker/index.jsx @@ -6,7 +6,6 @@ import { MuiColorInput } from "mui-color-input"; /** * * @param {*} id The ID of the component - * @param {*} label The Label of the component * @param {*} value The color value of the component * @param {*} error The error of the component * @param {*} onChange The Change handler function @@ -15,7 +14,6 @@ import { MuiColorInput } from "mui-color-input"; * Example usage: * * */ -const ColorPicker = ({ id, label, value, error, onChange, onBlur }) => { +const ColorPicker = ({ id, value, error, onChange, onBlur }) => { const theme = useTheme(); return ( @@ -31,7 +29,6 @@ const ColorPicker = ({ id, label, value, error, onChange, onBlur }) => { format="hex" value={value} id={id} - label={label} onChange={onChange} onBlur={onBlur} /> @@ -54,7 +51,6 @@ const ColorPicker = ({ id, label, value, error, onChange, onBlur }) => { ColorPicker.propTypes = { id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, value: PropTypes.string, error: PropTypes.string, onChange: PropTypes.func.isRequired, diff --git a/Client/src/Components/TabPanels/Status/ContentPanel.jsx b/Client/src/Components/TabPanels/Status/ContentPanel.jsx index 2b78039bf..cbc4cad1c 100644 --- a/Client/src/Components/TabPanels/Status/ContentPanel.jsx +++ b/Client/src/Components/TabPanels/Status/ContentPanel.jsx @@ -1,30 +1,37 @@ import { useState, useContext, useEffect } from "react"; import { Button, Box, Stack, Typography } from "@mui/material"; -import ConfigBox from "../../../Components/ConfigBox"; import { useTheme } from "@emotion/react"; import TabPanel from "@mui/lab/TabPanel"; + +import ConfigBox from "../../../Components/ConfigBox"; import { StatusFormContext } from "../../../Pages/Status/CreateStatusContext"; import { useSelector } from "react-redux"; -import { logger } from "../../../Utils/Logger" +import { logger } from "../../../Utils/Logger"; import { createToast } from "../../../Utils/toastUtils"; import { networkService } from "../../../main"; import ServersList from "./ServersList"; - +import Checkbox from "../../Inputs/Checkbox"; /** * Content Panel is used to compose the second part of the status page - * for the servers/monitors to watch for in its public page presence and some + * for the servers/monitors to watch for in its public page presence and some * other server related configurations etc - * + * */ const ContentPanel = () => { const theme = useTheme(); - const { form, setForm, errors, setErrors } = useContext(StatusFormContext); + const { + form, + setForm, + errors, + setErrors, + handleBlur, + handelCheckboxChange, + } = useContext(StatusFormContext); const [cards, setCards] = useState([]); - const {user, authToken } = useSelector((state) => state.auth); + const { user, authToken } = useSelector((state) => state.auth); const [monitors, setMonitors] = useState([]); - useEffect(() => { const fetchMonitors = async () => { try { @@ -34,10 +41,10 @@ const ContentPanel = () => { limit: null, // donot return any checks for the monitors types: ["http"], // status page is available only for the uptime type }); - if(response.data.data.monitors.length==0){ - setErrors({monitors: "Please config monitors to setup status page"}) + if (response.data.data.monitors.length == 0) { + setErrors({ monitors: "Please config monitors to setup status page" }); } - const fullMonitors = response.data.data.monitors ; + const fullMonitors = response.data.data.monitors; setMonitors(fullMonitors); if (form.monitors.length > 0) { const initiCards = form.monitors.map((mid, idx) => ({ @@ -52,12 +59,12 @@ const ContentPanel = () => { createToast({ body: "Failed to fetch monitors data" }); logger.error("Failed to fetch monitors", error); } - }; + }; fetchMonitors(); }, [user, authToken]); const handleAddNew = () => { if (cards.length === monitors.length) return; - const newCards = [...cards, { id: "" + Math.random(),val:{} }]; + const newCards = [...cards, { id: "" + Math.random(), val: {} }]; setCards(newCards); }; const removeCard = (id) => { @@ -96,10 +103,10 @@ const ContentPanel = () => { - { Add new - {cards.length > 0 && ( - - - - )} + + + {errors["monitors"] && ( { {errors["monitors"]} )} - + @@ -167,23 +168,22 @@ const ContentPanel = () => { Show more details on the status page - {/* + - */} + /> + diff --git a/Client/src/Components/TabPanels/Status/GeneralSettingsPanel.jsx b/Client/src/Components/TabPanels/Status/GeneralSettingsPanel.jsx index 737b75500..98b5dbf5e 100644 --- a/Client/src/Components/TabPanels/Status/GeneralSettingsPanel.jsx +++ b/Client/src/Components/TabPanels/Status/GeneralSettingsPanel.jsx @@ -1,38 +1,34 @@ import { useState, useRef, useContext } from "react"; import { Box, Button, Stack, Typography } from "@mui/material"; -import ConfigBox from "../../../Components/ConfigBox"; import { useTheme } from "@emotion/react"; import TabPanel from "@mui/lab/TabPanel"; +import ImageIcon from "@mui/icons-material/Image"; + +import ConfigBox from "../../../Components/ConfigBox"; import TextInput from "../../Inputs/TextInput"; import ImageField from "../../Inputs/Image"; import timezones from "../../../Utils/timezones.json"; import Select from "../../Inputs/Select"; -import { - logoImageValidation, - publicPageGeneralSettingsValidation, -} from "../../../Validation/validation"; -import { buildErrors } from "../../../Validation/error"; +import { logoImageValidation } from "../../../Validation/validation"; import { formatBytes } from "../../../Utils/fileUtils"; import ProgressUpload from "../../ProgressBars"; -import ImageIcon from "@mui/icons-material/Image"; -import { HttpAdornment } from "../../Inputs/TextInput/Adornments"; import { StatusFormContext } from "../../../Pages/Status/CreateStatusContext"; import ColorPicker from "../../Inputs/ColorPicker"; +import Checkbox from "../../Inputs/Checkbox"; /** * General settings panel is ued to compose part of the public static page * for general informations like company name, subdomain url, logo and color etc */ const GeneralSettingsPanel = () => { - const theme = useTheme(); - const { form, setForm, errors, setErrors } = useContext(StatusFormContext); + const theme = useTheme(); + const { form, setForm, errors, setErrors, handleBlur, handleChange, handelCheckboxChange } = + useContext(StatusFormContext); const [logo, setLogo] = useState(form.logo); const [progress, setProgress] = useState({ value: 0, isLoading: false }); const intervalRef = useRef(null); - const SUBDOAMIN_PREFIX = - import.meta.env.VITE_STATUS_PAGE_SUBDOMAIN_PREFIX ?? "http://localhost/"; - const STATUS_PAGE = import.meta.env.VITE_STATU_PAGE_URL?? "status-page"; + const STATUS_PAGE = import.meta.env.VITE_STATU_PAGE_URL ?? "status-page"; // Clears specific error from errors state const clearError = (err) => { @@ -59,29 +55,6 @@ const GeneralSettingsPanel = () => { ...prev, color: newValue, })); - } - - const handleChange = (event) => { - event.preventDefault(); - const { value, id, name } = event.target; - setForm((prev) => ({ - ...prev, - [id ?? name]: value, - })); - }; - - const handleBlur = (event) => { - event.preventDefault(); - const { value, id } = event.target; - const { error } = publicPageGeneralSettingsValidation.validate( - { [id]: value }, - { - abortEarly: false, - } - ); - setErrors((prev) => { - return buildErrors(prev, id, error); - }); }; const validateField = (toValidate, schema, name = "logo") => { @@ -105,7 +78,7 @@ const GeneralSettingsPanel = () => { name: pic.name, type: pic.type, size: pic.size, - } + }; setProgress((prev) => ({ ...prev, isLoading: true })); setLogo(newLogo); setForm({ ...form, logo: newLogo }); @@ -141,13 +114,14 @@ const GeneralSettingsPanel = () => { - {/* */} + /> @@ -176,13 +150,7 @@ const GeneralSettingsPanel = () => { type="url" label="Your status page address" disabled - value={form.url ?? STATUS_PAGE} - startAdornment={ - - } + value={form.url ?? "/" + STATUS_PAGE} onChange={handleChange} onBlur={handleBlur} helperText={errors["url"]} @@ -210,46 +178,67 @@ const GeneralSettingsPanel = () => { items={timezones} error={errors["display-timezone"]} /> -