mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-24 10:39:40 -06:00
Feat: Uptime Monitor Filters
This commit is contained in:
109
src/Components/FilterHeader/index.jsx
Normal file
109
src/Components/FilterHeader/index.jsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import {
|
||||
Checkbox,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Select,
|
||||
} from "@mui/material";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import PropTypes from "prop-types";
|
||||
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
|
||||
|
||||
const FilterHeader = ({ header, options, value, onChange, multiple = true }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const selectStyles = {
|
||||
"& .MuiOutlinedInput-input": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
"& .MuiSelect-icon": {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
"&:hover .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
};
|
||||
|
||||
const menuItemStyles = {
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FormControl
|
||||
sx={{ m: theme.spacing(2), minWidth: 120 }}
|
||||
size="small"
|
||||
>
|
||||
<InputLabel
|
||||
sx={{
|
||||
color: theme.palette.primary.contrastText,
|
||||
"&.Mui-focused": {
|
||||
display: "none",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{header}
|
||||
</InputLabel>
|
||||
<Select
|
||||
multiple={multiple}
|
||||
IconComponent={(props) => (
|
||||
<AddCircleOutlineIcon
|
||||
{...props}
|
||||
sx={{ fontSize: "medium" }}
|
||||
/>
|
||||
)}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
renderValue={(selected) => selected.join(", ")}
|
||||
sx={selectStyles}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<MenuItem
|
||||
key={option}
|
||||
value={option}
|
||||
sx={menuItemStyles}
|
||||
>
|
||||
<Checkbox
|
||||
checked={value.includes(option)}
|
||||
size="small"
|
||||
/>
|
||||
<ListItemText
|
||||
primary={
|
||||
option === "http"
|
||||
? "HTTP(S)"
|
||||
: option === "ping"
|
||||
? "Ping"
|
||||
: option === "docker"
|
||||
? "Docker"
|
||||
: option === "port"
|
||||
? "Port"
|
||||
: option
|
||||
}
|
||||
/>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
FilterHeader.propTypes = {
|
||||
header: PropTypes.string,
|
||||
options: PropTypes.arrayOf(PropTypes.string),
|
||||
value: PropTypes.arrayOf(PropTypes.string),
|
||||
onChange: PropTypes.func,
|
||||
multiple: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default FilterHeader;
|
||||
109
src/Pages/Uptime/Monitors/Components/Filter/index.jsx
Normal file
109
src/Pages/Uptime/Monitors/Components/Filter/index.jsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import { useTheme } from "@emotion/react";
|
||||
import PropTypes from "prop-types";
|
||||
import FilterHeader from "../../../../../Components/FilterHeader";
|
||||
import { useMemo, useState } from "react";
|
||||
import { Box, Button } from "@mui/material";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
|
||||
const Filter = ({ selectedTypes, setSelectedTypes, setToFilterStatus, setToFilterActive }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const [selectedState, setSelectedState] = useState([]);
|
||||
const [selectedStatus, setSelectedStatus] = useState([]);
|
||||
|
||||
const handleTypeChange = (event) => {
|
||||
setSelectedTypes(event.target.value);
|
||||
};
|
||||
|
||||
const handleStatusChange = (event) => {
|
||||
const selectedValues = event.target.value;
|
||||
setSelectedStatus(selectedValues);
|
||||
|
||||
if (selectedValues.length === 0 || selectedValues.length === 2) {
|
||||
setToFilterStatus(null);
|
||||
} else {
|
||||
setToFilterStatus(selectedValues[0] === "Up" ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
const handleStateChange = (event) => {
|
||||
const selectedValues = event.target.value;
|
||||
setSelectedState(selectedValues);
|
||||
|
||||
if (selectedValues.length === 0 || selectedValues.length === 2) {
|
||||
setToFilterActive(null);
|
||||
} else {
|
||||
setToFilterActive(selectedValues[0] === "Active" ? "true" : "false");
|
||||
}
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setSelectedState([]);
|
||||
setSelectedTypes([]);
|
||||
setSelectedStatus([]);
|
||||
setToFilterStatus(null);
|
||||
setToFilterActive(null);
|
||||
};
|
||||
|
||||
const isFilterActive = useMemo(() => {
|
||||
return selectedTypes.length > 0 || selectedState.length > 0 || selectedStatus.length > 0;
|
||||
}, [selectedState, selectedTypes, selectedStatus]);
|
||||
|
||||
const typeOptions = ["http", "ping", "docker", "port"];
|
||||
const statusOptions = ["Up", "Down"];
|
||||
const stateOptions = ["Active", "Paused"];
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
ml: theme.spacing(80),
|
||||
gap: theme.spacing(2),
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
color={theme.palette.primary.contrastText}
|
||||
onClick={handleReset}
|
||||
variant="contained"
|
||||
endIcon={<ClearIcon />}
|
||||
sx={{
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
visibility: isFilterActive ? "visible" : "hidden",
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<FilterHeader
|
||||
header="Type"
|
||||
options={typeOptions}
|
||||
value={selectedTypes}
|
||||
onChange={handleTypeChange}
|
||||
/>
|
||||
<FilterHeader
|
||||
header="Status"
|
||||
options={statusOptions}
|
||||
value={selectedStatus}
|
||||
onChange={handleStatusChange}
|
||||
/>
|
||||
<FilterHeader
|
||||
header="State"
|
||||
options={stateOptions}
|
||||
value={selectedState}
|
||||
onChange={handleStateChange}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Filter.propTypes = {
|
||||
selectedTypes: PropTypes.arrayOf(PropTypes.string),
|
||||
setSelectedTypes: PropTypes.func,
|
||||
setToFilterStatus: PropTypes.func,
|
||||
setToFilterActive: PropTypes.func,
|
||||
};
|
||||
|
||||
export default Filter;
|
||||
@@ -28,6 +28,7 @@ const SearchComponent = ({ monitors = [], onSearchChange, setIsSearching }) => {
|
||||
width="25%"
|
||||
minWidth={150}
|
||||
ml="auto"
|
||||
mt={2}
|
||||
>
|
||||
<Search
|
||||
options={monitors}
|
||||
|
||||
@@ -13,6 +13,7 @@ import CreateMonitorHeader from "../../../Components/MonitorCreateHeader";
|
||||
import Fallback from "../../../Components/Fallback";
|
||||
import GenericFallback from "../../../Components/GenericFallback";
|
||||
import SearchComponent from "./Components/SearchComponent";
|
||||
import Filter from "./Components/Filter";
|
||||
|
||||
import MonitorCountHeader from "../../../Components/MonitorCountHeader";
|
||||
|
||||
@@ -69,6 +70,9 @@ const UptimeMonitors = () => {
|
||||
const [sort, setSort] = useState(undefined);
|
||||
const [isSearching, setIsSearching] = useState(false);
|
||||
const [monitorUpdateTrigger, setMonitorUpdateTrigger] = useState(false);
|
||||
const [selectedTypes, setSelectedTypes] = useState([]);
|
||||
const [toFilterStatus, setToFilterStatus] = useState(null);
|
||||
const [toFilterActive, setToFilterActive] = useState(null);
|
||||
|
||||
// Utils
|
||||
const theme = useTheme();
|
||||
@@ -103,6 +107,19 @@ const UptimeMonitors = () => {
|
||||
types: TYPES,
|
||||
monitorUpdateTrigger,
|
||||
});
|
||||
|
||||
let field = sort?.field;
|
||||
let filter = search;
|
||||
if (toFilterStatus !== null) {
|
||||
field = "status";
|
||||
filter = toFilterStatus;
|
||||
} else if (toFilterActive !== null) {
|
||||
field = "isActive";
|
||||
filter = toFilterActive;
|
||||
} else {
|
||||
field = sort?.field;
|
||||
filter = search;
|
||||
}
|
||||
|
||||
const [
|
||||
monitorsWithChecks,
|
||||
@@ -111,12 +128,12 @@ const UptimeMonitors = () => {
|
||||
monitorsWithChecksNetworkError,
|
||||
] = useFetchMonitorsWithChecks({
|
||||
teamId,
|
||||
types: TYPES,
|
||||
types: selectedTypes && selectedTypes.length > 0 ? selectedTypes : TYPES,
|
||||
limit: 25,
|
||||
page: page,
|
||||
rowsPerPage: rowsPerPage,
|
||||
filter: search,
|
||||
field: sort?.field,
|
||||
filter: filter,
|
||||
field: field,
|
||||
order: sort?.order,
|
||||
monitorUpdateTrigger,
|
||||
});
|
||||
@@ -179,6 +196,13 @@ const UptimeMonitors = () => {
|
||||
monitorCount={monitorsSummary?.totalMonitors}
|
||||
heading={"Uptime monitors"}
|
||||
></MonitorCountHeader>
|
||||
<Filter
|
||||
selectedTypes={selectedTypes}
|
||||
setSelectedTypes={setSelectedTypes}
|
||||
toFilterStatus={toFilterStatus}
|
||||
setToFilterStatus={setToFilterStatus}
|
||||
setToFilterActive={setToFilterActive}
|
||||
/>
|
||||
<SearchComponent
|
||||
monitors={monitors}
|
||||
onSearchChange={setSearch}
|
||||
|
||||
Reference in New Issue
Block a user