controls
This commit is contained in:
1 parent
69018a4944
commit
c2dece862c
4 files changed
+208
-10
No files matched your search
@@ -1,11 +1,92 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { Select } from "@/Components/v2/inputs";
|
||||
export const FilterControls = () => {
|
||||
import { Select, Button } from "@/Components/v2/inputs";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
|
||||
import type { MonitorType } from "@/Types/Monitor";
|
||||
import { Typography, useTheme } from "@mui/material";
|
||||
|
||||
const types = ["http", "ping", "port", "docker"];
|
||||
const statuses = ["up", "down"];
|
||||
const states = ["active", "paused"];
|
||||
|
||||
export const FilterControls = ({
|
||||
selectedTypes,
|
||||
setSelectedTypes,
|
||||
selectedStatus,
|
||||
setSelectedStatus,
|
||||
selectedState,
|
||||
setSelectedState,
|
||||
}: {
|
||||
selectedTypes: MonitorType[];
|
||||
setSelectedTypes: React.Dispatch<React.SetStateAction<MonitorType[]>>;
|
||||
selectedStatus: string;
|
||||
setSelectedStatus: React.Dispatch<React.SetStateAction<string>>;
|
||||
selectedState: string;
|
||||
setSelectedState: React.Dispatch<React.SetStateAction<string>>;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isFilterActive =
|
||||
selectedTypes.length > 0 || selectedStatus !== "" || selectedState !== "";
|
||||
return (
|
||||
<Stack direction="row">
|
||||
<Select placeholder="Type"></Select>
|
||||
<Select placeholder="Status" />
|
||||
<Select placeholder="Priority" />
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(2)}
|
||||
>
|
||||
<Select
|
||||
multiple
|
||||
placeholder="Type"
|
||||
value={selectedTypes}
|
||||
onChange={(e) => setSelectedTypes(e.target.value as MonitorType[])}
|
||||
>
|
||||
{types.map((type) => (
|
||||
<MenuItem
|
||||
key={type}
|
||||
value={type}
|
||||
>
|
||||
<Typography textTransform={"capitalize"}>{type}</Typography>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
placeholder="Status"
|
||||
value={selectedStatus}
|
||||
onChange={(e) => setSelectedStatus(e.target.value)}
|
||||
>
|
||||
{statuses.map((status) => (
|
||||
<MenuItem
|
||||
key={status}
|
||||
value={status}
|
||||
>
|
||||
<Typography textTransform={"capitalize"}>{status}</Typography>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
placeholder="State"
|
||||
value={selectedState}
|
||||
onChange={(e) => setSelectedState(e.target.value)}
|
||||
>
|
||||
{states.map((state) => (
|
||||
<MenuItem
|
||||
key={state}
|
||||
value={state}
|
||||
>
|
||||
<Typography textTransform={"capitalize"}>{state}</Typography>
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{isFilterActive && (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
setSelectedTypes([]);
|
||||
setSelectedStatus("");
|
||||
setSelectedState("");
|
||||
}}
|
||||
>
|
||||
Clear Filters
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -1,24 +1,71 @@
|
||||
import { useGet } from "@/Hooks/UseApi";
|
||||
import { MonitorBasePageWithStates } from "@/Components/v2/design-elements";
|
||||
import { type Monitor } from "@/Types/Monitor";
|
||||
import type { Monitor, MonitorType, MonitorsWithChecksResponse } from "@/Types/Monitor";
|
||||
import { FilterControls } from "@/Components/v2/monitors";
|
||||
import { useState, useMemo } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import type { RootState } from "@/Types/state";
|
||||
|
||||
const UptimeMonitorsPage = () => {
|
||||
// Redux state
|
||||
const rowsPerPage = useSelector((state: RootState) => state.ui.monitors.rowsPerPage);
|
||||
|
||||
// Local state
|
||||
const [selectedTypes, setSelectedTypes] = useState<MonitorType[]>([]);
|
||||
const [selectedStatus, setSelectedStatus] = useState<string>("");
|
||||
const [selectedState, setSelectedState] = useState<string>("");
|
||||
const [page, setPage] = useState(0);
|
||||
const [search, setSearch] = useState("");
|
||||
const [sort, setSort] = useState<
|
||||
{ field: string; order: "asc" | "desc" } | undefined
|
||||
>();
|
||||
|
||||
// Build URL for monitors with checks
|
||||
const monitorsWithChecksUrl = useMemo(() => {
|
||||
const params = new URLSearchParams();
|
||||
const types =
|
||||
selectedTypes.length > 0 ? selectedTypes : ["http", "ping", "docker", "port"];
|
||||
types.forEach((type) => params.append("type", type));
|
||||
params.append("limit", "25");
|
||||
if (page) params.append("page", String(page));
|
||||
if (rowsPerPage) params.append("rowsPerPage", String(rowsPerPage));
|
||||
if (search) params.append("filter", search);
|
||||
if (sort?.field) params.append("field", sort.field);
|
||||
if (sort?.order) params.append("order", sort.order);
|
||||
return `/monitors/team/with-checks?${params.toString()}`;
|
||||
}, [selectedTypes, page, rowsPerPage, search, sort]);
|
||||
|
||||
// Data fetching
|
||||
const {
|
||||
data: monitors,
|
||||
isLoading,
|
||||
error,
|
||||
} = useGet<Monitor[]>("/monitors/team?type=http&type=ping&type=port&type=docker");
|
||||
|
||||
const {
|
||||
data: monitorsWithChecksData,
|
||||
isLoading: monitorsWithChecksLoading,
|
||||
error: monitorsWithChecksError,
|
||||
} = useGet<MonitorsWithChecksResponse>(monitorsWithChecksUrl);
|
||||
|
||||
const { monitors: monitorsWithChecks, summary, count } = monitorsWithChecksData ?? {};
|
||||
|
||||
return (
|
||||
<MonitorBasePageWithStates
|
||||
loading={isLoading}
|
||||
error={error}
|
||||
loading={isLoading || monitorsWithChecksLoading}
|
||||
error={error || monitorsWithChecksError}
|
||||
items={monitors || []}
|
||||
page="uptime"
|
||||
actionLink="/uptime/create"
|
||||
>
|
||||
<FilterControls />
|
||||
<FilterControls
|
||||
selectedTypes={selectedTypes}
|
||||
setSelectedTypes={setSelectedTypes}
|
||||
selectedStatus={selectedStatus}
|
||||
setSelectedStatus={setSelectedStatus}
|
||||
selectedState={selectedState}
|
||||
setSelectedState={setSelectedState}
|
||||
/>
|
||||
<pre>{JSON.stringify(monitors, null, 2)}</pre>
|
||||
</MonitorBasePageWithStates>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
import type { Check } from "@/Types/Check";
|
||||
export type MonitorStatus = "up" | "down" | "initializing";
|
||||
|
||||
export const MonitorTypes = [
|
||||
"http",
|
||||
"ping",
|
||||
"pagespeed",
|
||||
"hardware",
|
||||
"docker",
|
||||
"port",
|
||||
"game",
|
||||
"unknown",
|
||||
] as const;
|
||||
export type MonitorType = (typeof MonitorTypes)[number];
|
||||
|
||||
export interface Monitor {
|
||||
checks: Check[];
|
||||
createdAt: string;
|
||||
@@ -18,3 +30,21 @@ export interface Monitor {
|
||||
__v: number;
|
||||
_id: string;
|
||||
}
|
||||
|
||||
export interface MonitorWithChecks extends Monitor {
|
||||
checks: Check[];
|
||||
uptimePercentage?: number;
|
||||
}
|
||||
|
||||
export interface MonitorsSummary {
|
||||
totalMonitors: number;
|
||||
totalUp: number;
|
||||
totalDown: number;
|
||||
totalPaused: number;
|
||||
}
|
||||
|
||||
export interface MonitorsWithChecksResponse {
|
||||
count: number;
|
||||
monitors: MonitorWithChecks[];
|
||||
summary: MonitorsSummary;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
export interface AuthState {
|
||||
isLoading: boolean;
|
||||
authToken: string;
|
||||
user: string;
|
||||
success: boolean | null;
|
||||
msg: string | null;
|
||||
}
|
||||
|
||||
export interface UIState {
|
||||
monitors: {
|
||||
rowsPerPage: number;
|
||||
};
|
||||
team: {
|
||||
rowsPerPage: number;
|
||||
};
|
||||
maintenance: {
|
||||
rowsPerPage: number;
|
||||
};
|
||||
infrastructure: {
|
||||
rowsPerPage: number;
|
||||
};
|
||||
sidebar: {
|
||||
collapsed: boolean;
|
||||
};
|
||||
mode: "light" | "dark";
|
||||
showURL: boolean;
|
||||
greeting: {
|
||||
index: number;
|
||||
lastUpdate: string | null;
|
||||
};
|
||||
timezone: string;
|
||||
distributedUptimeEnabled: boolean;
|
||||
language: string;
|
||||
starPromptOpen: boolean;
|
||||
}
|
||||
|
||||
export interface RootState {
|
||||
auth: AuthState;
|
||||
ui: UIState;
|
||||
}
|
||||
Reference in new issue
Block a user