Merge pull request #1927 from bluewave-labs/fix/uptime-refactor

fix: uptime refactor
This commit is contained in:
Alexander Holliday
2025-03-14 11:16:21 -07:00
committed by GitHub
5 changed files with 198 additions and 26 deletions

View File

@@ -58,7 +58,7 @@ const BarChart = ({ checks = [] }) => {
<>
<Typography>
{formatDateWithTz(
check.createdAt,
check.updatedAt,
"ddd, MMMM D, YYYY, HH:mm A",
uiTimezone
)}

View File

@@ -0,0 +1,71 @@
import { useEffect, useState } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
import { useTheme } from "@emotion/react";
import { useMonitorUtils } from "./useMonitorUtils";
export const useFetchMonitorsWithChecks = ({
teamId,
types,
limit,
page,
rowsPerPage,
filter,
field,
order,
triggerUpdate,
}) => {
const [isLoading, setIsLoading] = useState(false);
const [count, setCount] = useState(undefined);
const [monitors, setMonitors] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
const theme = useTheme();
const { getMonitorWithPercentage } = useMonitorUtils();
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsWithChecksByTeamId({
teamId,
limit,
types,
page,
rowsPerPage,
filter,
field,
order,
});
const { count, monitors } = res?.data?.data ?? {};
const mappedMonitors = monitors.map((monitor) =>
getMonitorWithPercentage(monitor, theme)
);
setMonitors(mappedMonitors);
setCount(count?.monitorsCount ?? 0);
} catch (error) {
console.error(error);
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [
field,
filter,
getMonitorWithPercentage,
limit,
order,
page,
rowsPerPage,
teamId,
theme,
types,
]);
return [monitors, count, isLoading, networkError];
};
export default useFetchMonitorsWithChecks;

View File

@@ -0,0 +1,37 @@
import { useEffect, useState } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
export const useFetchMonitorsWithSummary = ({ teamId, types }) => {
const [isLoading, setIsLoading] = useState(false);
const [monitors, setMonitors] = useState(undefined);
const [monitorsSummary, setMonitorsSummary] = useState(undefined);
const [networkError, setNetworkError] = useState(false);
useEffect(() => {
const fetchMonitors = async () => {
try {
setIsLoading(true);
const res = await networkService.getMonitorsWithSummaryByTeamId({
teamId,
types,
});
const { monitors, summary } = res?.data?.data ?? {};
setMonitors(monitors);
setMonitorsSummary(summary);
} catch (error) {
console.error(error);
setNetworkError(true);
createToast({
body: error.message,
});
} finally {
setIsLoading(false);
}
};
fetchMonitors();
}, [teamId, types]);
return [monitors, monitorsSummary, isLoading, networkError];
};
export default useFetchMonitorsWithSummary;

View File

@@ -1,3 +1,8 @@
// Required Data
// 1. Monitor summary
// 2. List of monitors filtered by search term with 25 checks each
// 2a.List of monitors must have the total number of monitors that match.
// Components
import Breadcrumbs from "../../../Components/Breadcrumbs";
import Greeting from "../../../Utils/greeting";
@@ -23,9 +28,11 @@ import useMonitorsFetch from "./Hooks/useMonitorsFetch";
import { useSelector, useDispatch } from "react-redux";
import { setRowsPerPage } from "../../../Features/UI/uiSlice";
import PropTypes from "prop-types";
import useFetchMonitorsWithSummary from "../../../Hooks/useFetchMonitorsWithSummary";
import useFetchMonitorsWithChecks from "../../../Hooks/useFetchMonitorsWithChecks";
const BREADCRUMBS = [{ name: `Uptime`, path: "/uptime" }];
const TYPES = ["http", "ping", "docker", "port"];
const CreateMonitorButton = ({ shouldRender }) => {
// Utils
const navigate = useNavigate();
@@ -89,23 +96,32 @@ const UptimeMonitors = () => {
}, []);
const teamId = user.teamId;
const {
monitorsAreLoading,
monitors,
filteredMonitors,
monitorsSummary,
networkError,
} = useMonitorsFetch({
const [monitors, monitorsSummary, monitorsWithSummaryIsLoading, networkError] =
useFetchMonitorsWithSummary({
teamId,
types: TYPES,
});
const [
monitorsWithChecks,
monitorsWithChecksCount,
monitorsWithChecksIsLoading,
monitorsWithChecksNetworkError,
] = useFetchMonitorsWithChecks({
teamId,
types: TYPES,
limit: 25,
page: page,
rowsPerPage: rowsPerPage,
filter: search,
field: sort?.field,
order: sort?.order,
triggerUpdate: monitorUpdateTrigger,
triggerUpdate,
});
const totalMonitors = monitorsSummary?.totalMonitors;
const isLoading = monitorsWithSummaryIsLoading || monitorsWithChecksIsLoading;
if (networkError) {
return (
<GenericFallback>
@@ -121,8 +137,9 @@ const UptimeMonitors = () => {
);
}
if (
!monitorsAreLoading &&
(totalMonitors === 0 || typeof totalMonitors === "undefined")
!isLoading &&
(monitorsSummary?.totalMonitors === 0 ||
typeof monitorsSummary?.totalMonitors === "undefined")
) {
return (
<Fallback
@@ -147,19 +164,19 @@ const UptimeMonitors = () => {
<Breadcrumbs list={BREADCRUMBS} />
<CreateMonitorHeader
isAdmin={isAdmin}
shouldRender={!monitorsAreLoading}
shouldRender={!isLoading}
path="/uptime/create"
/>
<Greeting type="uptime" />
<StatusBoxes
monitorsSummary={monitorsSummary}
shouldRender={!monitorsAreLoading}
shouldRender={!monitorsWithSummaryIsLoading}
/>
<Stack direction={"row"}>
<MonitorCountHeader
shouldRender={monitors?.length > 0 && !monitorsAreLoading}
monitorCount={totalMonitors}
shouldRender={monitors?.length > 0 && !monitorsWithSummaryIsLoading}
monitorCount={monitorsSummary?.totalMonitors}
heading={"Uptime monitors"}
></MonitorCountHeader>
<SearchComponent
@@ -170,19 +187,14 @@ const UptimeMonitors = () => {
</Stack>
<UptimeDataTable
isAdmin={isAdmin}
isLoading={monitorsAreLoading}
filteredMonitors={filteredMonitors}
monitors={monitors}
monitorCount={totalMonitors}
isSearching={isSearching}
filteredMonitors={monitorsWithChecks}
sort={sort}
setSort={setSort}
setSearch={setSearch}
isSearching={isSearching}
monitorsAreLoading={monitorsAreLoading}
triggerUpdate={triggerUpdate}
monitorsAreLoading={monitorsWithChecksIsLoading}
/>
<Pagination
itemCount={totalMonitors}
itemCount={monitorsWithChecksCount}
paginationLabel="monitors"
page={page}
rowsPerPage={rowsPerPage}

View File

@@ -1033,6 +1033,58 @@ class NetworkService {
return this.axiosInstance.delete(`/status-page/${encodedUrl}`, {});
}
// ************************************
// Fetch monitors with summary by TeamID
// ************************************
async getMonitorsWithSummaryByTeamId(config) {
const { teamId, types } = config;
const params = new URLSearchParams();
if (types) {
types.forEach((type) => {
params.append("type", type);
});
}
return this.axiosInstance.get(
`/monitors/summary/team/${teamId}?${params.toString()}`,
{
headers: {
"Content-Type": "application/json",
},
}
);
}
// ************************************
// Fetch monitors with checks by TeamID
// ************************************
async getMonitorsWithChecksByTeamId(config) {
const { teamId, limit, types, page, rowsPerPage, filter, field, order } = config;
const params = new URLSearchParams();
if (limit) params.append("limit", limit);
if (types) {
types.forEach((type) => {
params.append("type", type);
});
}
if (page) params.append("page", page);
if (rowsPerPage) params.append("rowsPerPage", rowsPerPage);
if (filter) params.append("filter", filter);
if (field) params.append("field", field);
if (order) params.append("order", order);
return this.axiosInstance.get(
`/monitors/team/${teamId}/with-checks?${params.toString()}`,
{
headers: {
"Content-Type": "application/json",
},
}
);
}
}
export default NetworkService;