- Replace Doc icon with Reorder icon
- Replace Text input with Search component - Extend Search component to accept start and end adorment
This commit is contained in:
1 parent
d844078ed7
commit
23d97f8e56
8 files changed
+122
-53
No files matched your search
@@ -54,6 +54,8 @@ const Search = ({
|
||||
isAdorned = true,
|
||||
error,
|
||||
disabled,
|
||||
startAdornment,
|
||||
endAdornment
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
@@ -66,15 +68,15 @@ const Search = ({
|
||||
onInputChange={(_, newValue) => {
|
||||
handleInputChange(newValue);
|
||||
}}
|
||||
onChange={(_, newValue) => {
|
||||
handleChange && handleChange(newValue);
|
||||
onChange={(e, newValue) => {
|
||||
handleChange && handleChange(e, newValue);
|
||||
}}
|
||||
fullWidth
|
||||
freeSolo
|
||||
disabled={disabled}
|
||||
disableClearable
|
||||
options={options}
|
||||
getOptionLabel={(option) => option[filteredBy]}
|
||||
getOptionLabel={(option) => option[filteredBy]??""}
|
||||
renderInput={(params) => (
|
||||
<Stack>
|
||||
<Typography
|
||||
@@ -89,9 +91,13 @@ const Search = ({
|
||||
{...params}
|
||||
error={Boolean(error)}
|
||||
placeholder="Type to search"
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
...(isAdorned && { startAdornment: <SearchAdornment /> }),
|
||||
slotProps={{
|
||||
input: {
|
||||
...params.InputProps,
|
||||
...(isAdorned && { startAdornment: <SearchAdornment /> }),
|
||||
...(startAdornment && { startAdornment: startAdornment }),
|
||||
...(endAdornment && { endAdornment: endAdornment }),
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
"& fieldset": {
|
||||
@@ -187,7 +193,7 @@ Search.propTypes = {
|
||||
options: PropTypes.array.isRequired,
|
||||
filteredBy: PropTypes.string.isRequired,
|
||||
secondaryLabel: PropTypes.string,
|
||||
value: PropTypes.array,
|
||||
value: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
|
||||
inputValue: PropTypes.string.isRequired,
|
||||
handleInputChange: PropTypes.func.isRequired,
|
||||
handleChange: PropTypes.func,
|
||||
@@ -195,6 +201,8 @@ Search.propTypes = {
|
||||
sx: PropTypes.object,
|
||||
error: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
startAdornment: PropTypes.object,
|
||||
endAdornment: PropTypes.object
|
||||
};
|
||||
|
||||
export default Search;
|
||||
@@ -3,8 +3,8 @@ import { useTheme } from "@mui/material/styles";
|
||||
import PropTypes from "prop-types";
|
||||
import VisibilityOff from "@mui/icons-material/VisibilityOff";
|
||||
import Visibility from "@mui/icons-material/Visibility";
|
||||
import Docs from "../../../../assets/icons/docs.svg?react";
|
||||
import DeleteIcon from "../../../../assets/icons/trash-bin.svg?react";
|
||||
import ReorderRoundedIcon from '@mui/icons-material/ReorderRounded';
|
||||
import DeleteIcon from "../../../../assets/icons/trash-bin.svg?react";
|
||||
|
||||
export const HttpAdornment = ({ https, prefix }) => {
|
||||
const theme = useTheme();
|
||||
@@ -70,7 +70,7 @@ PasswordEndAdornment.propTypes = {
|
||||
export const ServerStartAdornment = () => {
|
||||
return (
|
||||
<InputAdornment position="start">
|
||||
<Docs />
|
||||
<ReorderRoundedIcon />
|
||||
</InputAdornment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import TextInput from "../../../../Inputs/TextInput";
|
||||
import { ServerStartAdornment, ServerEndAdornment } from "../../../../Inputs/TextInput/Adornments";
|
||||
import Search from "../../../../Inputs/Search";
|
||||
import {useState} from "react"
|
||||
|
||||
|
||||
const Server = ({ id, removeItem, value, onChange }) => {
|
||||
const Server = ({ id, removeItem, onChange, monitors, value, label }) => {
|
||||
const [search, setSearch] = useState("");
|
||||
const handleSearch = (val) => {
|
||||
setSearch(val);
|
||||
};
|
||||
return (
|
||||
<TextInput
|
||||
type="text"
|
||||
<Search
|
||||
id={id}
|
||||
multiple={false}
|
||||
isAdorned={false}
|
||||
options={monitors ? monitors : []}
|
||||
filteredBy="name"
|
||||
inputValue={search}
|
||||
value={value}
|
||||
startAdornment={<ServerStartAdornment />}
|
||||
endAdornment={
|
||||
<ServerEndAdornment
|
||||
@@ -13,10 +23,9 @@ const Server = ({ id, removeItem, value, onChange }) => {
|
||||
removeItem={removeItem}
|
||||
/>
|
||||
}
|
||||
id={id}
|
||||
value= {value}
|
||||
onChange ={ onChange }
|
||||
></TextInput>
|
||||
handleInputChange={handleSearch}
|
||||
handleChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,12 +13,13 @@ const CustomCard = React.forwardRef((props, ref) => (
|
||||
removeItem={props.removeCard}
|
||||
value={props.value}
|
||||
onChange={props.onChange}
|
||||
monitors={props.monitors}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
));
|
||||
|
||||
const MyCard = ({ id, index, moveCard, removeCard, value, onChange }) => {
|
||||
const MyCard = ({ id, index, moveCard, removeCard, value, onChange, monitors }) => {
|
||||
const ref = useRef(null);
|
||||
const [, drop] = useDrop({
|
||||
accept: ItemTypes.CARD,
|
||||
@@ -80,6 +81,7 @@ const MyCard = ({ id, index, moveCard, removeCard, value, onChange }) => {
|
||||
removeCard={removeCard}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
monitors={monitors}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useContext } from "react";
|
||||
import { useState, useCallback, useContext, useEffect } from "react";
|
||||
import { Button, Box, Stack, Typography } from "@mui/material";
|
||||
import ConfigBox from "../../../Components/ConfigBox";
|
||||
import { useTheme } from "@emotion/react";
|
||||
@@ -6,11 +6,38 @@ import TabPanel from "@mui/lab/TabPanel";
|
||||
import Card from "./Card";
|
||||
import update from "immutability-helper";
|
||||
import { StatusFormContext } from "../../../Pages/Status/CreateStatusContext";
|
||||
import { useSelector } from "react-redux";
|
||||
import { logger } from "../../../Utils/Logger"
|
||||
import { createToast } from "../../../Utils/toastUtils";
|
||||
import { networkService } from "../../../main";
|
||||
|
||||
const ContentPanel = () => {
|
||||
const theme = useTheme();
|
||||
const { form, setForm, errors, setErrors } = useContext(StatusFormContext);
|
||||
const [cards, setCards] = useState(form.monitors);
|
||||
const [cards, setCards] = useState(form.monitors.length>0? form.monitors.map((m, idx)=>({id: idx, val: m})): []);
|
||||
const {user, authToken } = useSelector((state) => state.auth);
|
||||
const [monitors, setMonitors] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchMonitors = async () => {
|
||||
try {
|
||||
const response = await networkService.getMonitorsByTeamId({
|
||||
authToken: authToken,
|
||||
teamId: user.teamId,
|
||||
limit: -1,
|
||||
types: ["http", "ping", "pagespeed", "hardware"],
|
||||
});
|
||||
if(response.data.data.monitors.length==0){
|
||||
setErrors({monitors: "Please config monitors to setup status page"})
|
||||
}
|
||||
setMonitors(response.data.data.monitors);
|
||||
} catch (error) {
|
||||
createToast({ body: "Failed to fetch monitors data" });
|
||||
logger.error("Failed to fetch monitors", error);
|
||||
}
|
||||
};
|
||||
fetchMonitors();
|
||||
}, [user, authToken]);
|
||||
|
||||
const moveCard = useCallback(
|
||||
(dragIndex, hoverIndex) => {
|
||||
@@ -27,31 +54,40 @@ const ContentPanel = () => {
|
||||
[cards]
|
||||
);
|
||||
|
||||
const handleCardChange = (event) => {
|
||||
const handleCardChange = (event, val) => {
|
||||
event.preventDefault();
|
||||
const { value, id } = event.target;
|
||||
let idx = cards.findIndex((a) => a.id == id);
|
||||
const { id } = event.target;
|
||||
let idx = cards.findIndex((a) => {
|
||||
let found = false;
|
||||
let optionIdx = id.indexOf("-option");
|
||||
if (optionIdx !== -1) found = a.id == id.substr(0, optionIdx);
|
||||
else found = a.id == id;
|
||||
return found;
|
||||
});
|
||||
let newCards;
|
||||
if (idx >= 0) {
|
||||
let x = JSON.parse(JSON.stringify(cards[idx]));
|
||||
x.url = value;
|
||||
x.val = val;
|
||||
newCards = update(cards, { $splice: [[idx, 1, x]] });
|
||||
setCards(newCards);
|
||||
} else {
|
||||
newCards = update(cards, { $push: [{ id: id, url: value }] });
|
||||
newCards = update(cards, { $push: [{ id: id, val: val }] });
|
||||
setCards(newCards);
|
||||
}
|
||||
setForm({ ...form, monitors: newCards });
|
||||
setForm({ ...form, monitors: newCards.map(c=>c.val) });
|
||||
};
|
||||
const handleAddNew = () => {
|
||||
if (cards.length === monitors.length) return;
|
||||
const newCards = [...cards, { id: "" + Math.random() }];
|
||||
setCards(newCards);
|
||||
setForm({ ...form, monitors: newCards });
|
||||
};
|
||||
const removeCard = (id) => {
|
||||
const newCards = cards.filter((c) => c?.id != id);
|
||||
setCards(newCards);
|
||||
setForm({ ...form, monitors: newCards });
|
||||
setForm({
|
||||
...form,
|
||||
monitors: newCards.filter((c) => c.val !== undefined).map((c) => c.val),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -107,7 +143,12 @@ const ContentPanel = () => {
|
||||
{" "}
|
||||
Servers list{" "}
|
||||
</Typography>
|
||||
<Button onClick={handleAddNew}>Add New</Button>
|
||||
<Button
|
||||
onClick={handleAddNew}
|
||||
disabled={monitors.length === 0 || monitors.length <= cards.length}
|
||||
>
|
||||
Add New
|
||||
</Button>
|
||||
</Stack>
|
||||
{cards.length > 0 && (
|
||||
<Stack
|
||||
@@ -115,18 +156,21 @@ const ContentPanel = () => {
|
||||
direction="column"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
{cards.map((card, idx) => (
|
||||
<Card
|
||||
key={idx}
|
||||
index={idx}
|
||||
id={card?.id ?? "" + Math.random()}
|
||||
text={"" + idx}
|
||||
moveCard={moveCard}
|
||||
removeCard={removeCard}
|
||||
value={card?.url ?? ""}
|
||||
onChange={handleCardChange}
|
||||
/>
|
||||
))}
|
||||
{cards.map((card, idx) => {
|
||||
return (
|
||||
<Card
|
||||
key={idx}
|
||||
index={idx}
|
||||
id={card?.id ?? "" + Math.random()}
|
||||
text={"" + idx}
|
||||
moveCard={moveCard}
|
||||
removeCard={removeCard}
|
||||
value={card.val ?? {}}
|
||||
onChange={handleCardChange}
|
||||
monitors={monitors}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
)}
|
||||
{errors["monitors"] && (
|
||||
|
||||
@@ -181,7 +181,7 @@ const CreateMaintenance = () => {
|
||||
setSearch(value);
|
||||
};
|
||||
|
||||
const handleSelectMonitors = (monitors) => {
|
||||
const handleSelectMonitors = (_, monitors) => {
|
||||
setForm({ ...form, monitors });
|
||||
const { error } = maintenanceWindowValidation.validate(
|
||||
{ monitors },
|
||||
|
||||
@@ -22,7 +22,7 @@ import { networkService } from "../../../main";
|
||||
const CreateStatus = ({ initForm }) => {
|
||||
const theme = useTheme();
|
||||
const mode = useSelector((state) => state.ui.mode);
|
||||
const {authToken} = useSelector((state) => state.auth);
|
||||
const { authToken } = useSelector((state) => state.auth);
|
||||
const {apiBaseUrl} = useSelector((state) => state.settings);
|
||||
const [tabIdx, setTabIdx] = useState(0);
|
||||
const [errors, setErrors] = useState({});
|
||||
@@ -46,7 +46,6 @@ import { networkService } from "../../../main";
|
||||
// showBarcode: false,
|
||||
}
|
||||
);
|
||||
|
||||
const setActiveTabOnErrors = () => {
|
||||
let newIdx = -1;
|
||||
Object.keys(errors).map((id) => {
|
||||
@@ -72,7 +71,6 @@ import { networkService } from "../../../main";
|
||||
delete form.logo;
|
||||
//let localData = {...form, monitors: form.monitors.map(m=>m.url)}
|
||||
let localData = {...form, monitors: form.monitors, theme: mode}
|
||||
|
||||
if (hasValidationErrors(localData, publicPageGeneralSettingsValidation, setErrors)) {
|
||||
setActiveTabOnErrors();
|
||||
return;
|
||||
@@ -85,7 +83,8 @@ import { networkService } from "../../../main";
|
||||
// if (error) return;
|
||||
|
||||
//form.logo = { ...logo, size: formatBytes(logo?.size) };
|
||||
let config = { authToken: authToken, url: apiBaseUrl, data: localData };
|
||||
localData = {...form, monitors: form.monitors.map(m=>m.url),theme: mode}
|
||||
let config = { authToken: authToken, url: "status-page", data: localData };
|
||||
try{
|
||||
const res = await networkService.createStatusPage(config)
|
||||
if (!res.status === 200) {
|
||||
|
||||
@@ -6,6 +6,8 @@ import CreateStatus from "./CreateStatus";
|
||||
import { useEffect, useState } from "react";
|
||||
import { networkService } from "../../main";
|
||||
import { useSelector } from "react-redux";
|
||||
import { createToast } from "../../Utils/toastUtils"
|
||||
import { logger } from "../../Utils/Logger";
|
||||
|
||||
const Status = () => {
|
||||
const theme = useTheme();
|
||||
@@ -13,13 +15,18 @@ const Status = () => {
|
||||
const {authToken} = useSelector((state) => state.auth);
|
||||
const {apiBaseUrl} = useSelector((state) => state.settings);
|
||||
const [initForm, setInitForm] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
const getStatusPage = async () => {
|
||||
let config = { authToken: authToken, url: apiBaseUrl };
|
||||
let res = await networkService.getStatusPageByUrl(config);
|
||||
if(res && res.data)
|
||||
setInitForm( res.data.data)
|
||||
let config = { authToken: authToken, url: "status-page" };
|
||||
try {
|
||||
let res = await networkService.getStatusPageByUrl(config);
|
||||
if(res && res.data)
|
||||
setInitForm( res.data.data)
|
||||
}catch (error) {
|
||||
createToast({ body: "Failed to fetch status page data" });
|
||||
logger.error("Failed to fetch status page", error);
|
||||
}
|
||||
|
||||
};
|
||||
getStatusPage();
|
||||
}, []);
|
||||
|
||||
Reference in new issue
Block a user