Fix: change height and witdth and Merge branch 'develop' into fix/placeholder-center-align

This commit is contained in:
karenvicent
2025-07-04 17:46:41 -04:00
8 changed files with 174 additions and 48 deletions

View File

@@ -88,14 +88,15 @@ const Fallback = ({
display: "flex",
borderStyle: "dashed",
height: {
xs: theme.spacing(200),
sm: theme.spacing(300),
md: theme.spacing(300),
sm: "50vh",
md: "70vh",
lg: "60vh",
xl: "55vh",
},
width: {
xs: theme.spacing(100),
sm: theme.spacing(210),
md: theme.spacing(250),
sm: "90%",
md: "50%",
lg: "40%",
},
padding: theme.spacing(10),
}}

View File

@@ -1,6 +1,7 @@
import { useState, useEffect } from "react";
import { networkService } from "../main";
import { createToast } from "../Utils/toastUtils";
import { useTranslation } from "react-i18next";
const useFetchChecksTeam = ({
status,
@@ -12,6 +13,7 @@ const useFetchChecksTeam = ({
page,
rowsPerPage,
enabled = true,
updateTrigger,
}) => {
const [checks, setChecks] = useState(undefined);
const [checksCount, setChecksCount] = useState(undefined);
@@ -49,7 +51,18 @@ const useFetchChecksTeam = ({
};
fetchChecks();
}, [status, sortOrder, limit, dateRange, filter, ack, page, rowsPerPage, enabled]);
}, [
status,
sortOrder,
limit,
dateRange,
filter,
ack,
page,
rowsPerPage,
enabled,
updateTrigger,
]);
return [checks, checksCount, isLoading, networkError];
};
@@ -66,6 +79,7 @@ const useFetchChecksByMonitor = ({
page,
rowsPerPage,
enabled = true,
updateTrigger,
}) => {
const [checks, setChecks] = useState(undefined);
const [checksCount, setChecksCount] = useState(undefined);
@@ -117,12 +131,13 @@ const useFetchChecksByMonitor = ({
page,
rowsPerPage,
enabled,
updateTrigger,
]);
return [checks, checksCount, isLoading, networkError];
};
const useFetchChecksSummaryByTeamId = () => {
const useFetchChecksSummaryByTeamId = ({ updateTrigger } = {}) => {
const [summary, setSummary] = useState(undefined);
const [isLoading, setIsLoading] = useState(false);
const [networkError, setNetworkError] = useState(false);
@@ -143,9 +158,56 @@ const useFetchChecksSummaryByTeamId = () => {
};
fetchSummary();
}, []);
}, [updateTrigger]);
return [summary, isLoading, networkError];
};
export { useFetchChecksByMonitor, useFetchChecksTeam, useFetchChecksSummaryByTeamId };
const useResolveIncident = () => {
const [isLoading, setIsLoading] = useState(false);
const { t } = useTranslation();
const resolveIncident = async (checkId, setUpdateTrigger) => {
try {
setIsLoading(true);
await networkService.updateCheckStatus({
checkId,
ack: true,
});
setUpdateTrigger((prev) => !prev);
} catch (error) {
createToast({ body: t("checkHooks.failureResolveOne") });
} finally {
setIsLoading(false);
}
};
return [resolveIncident, isLoading];
};
const useAckAllChecks = () => {
const [isLoading, setIsLoading] = useState(false);
const { t } = useTranslation();
const ackAllChecks = async (setUpdateTrigger) => {
try {
setIsLoading(true);
await networkService.updateAllChecksStatus({ ack: true });
setUpdateTrigger((prev) => !prev);
} catch (error) {
createToast({ body: t("checkHooks.failureResolveAll") });
} finally {
setIsLoading(false);
}
};
return [ackAllChecks, isLoading];
};
export {
useFetchChecksByMonitor,
useFetchChecksTeam,
useFetchChecksSummaryByTeamId,
useResolveIncident,
useAckAllChecks,
};

View File

@@ -15,13 +15,17 @@ import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { useFetchChecksTeam } from "../../../../Hooks/checkHooks";
import { useFetchChecksByMonitor } from "../../../../Hooks/checkHooks";
import { useResolveIncident } from "../../../../Hooks/checkHooks";
import { Button, Typography } from "@mui/material";
const IncidentTable = ({
shouldRender,
isLoading,
monitors,
selectedMonitor,
filter,
dateRange,
updateTrigger,
setUpdateTrigger,
}) => {
//Redux state
const uiTimezone = useSelector((state) => state.ui.timezone);
@@ -32,6 +36,9 @@ const IncidentTable = ({
const selectedMonitorDetails = monitors?.[selectedMonitor];
const selectedMonitorType = selectedMonitorDetails?.type;
//Hooks
const [resolveIncident, resolveLoading] = useResolveIncident();
const [checksMonitor, checksCountMonitor, isLoadingMonitor, networkErrorMonitor] =
useFetchChecksByMonitor({
monitorId: selectedMonitor === "0" ? undefined : selectedMonitor,
@@ -45,6 +52,7 @@ const IncidentTable = ({
page: page,
rowsPerPage: rowsPerPage,
enabled: selectedMonitor !== "0",
updateTrigger,
});
const [checksTeam, checksCountTeam, isLoadingTeam, networkErrorTeam] =
@@ -58,11 +66,12 @@ const IncidentTable = ({
page: page,
rowsPerPage: rowsPerPage,
enabled: selectedMonitor === "0",
updateTrigger,
});
const checks = selectedMonitor === "0" ? checksTeam : checksMonitor;
const checksCount = selectedMonitor === "0" ? checksCountTeam : checksCountMonitor;
const isLoading = isLoadingTeam || isLoadingMonitor;
isLoading = isLoadingTeam || isLoadingMonitor;
const networkError = selectedMonitor === "0" ? networkErrorTeam : networkErrorMonitor;
const { t } = useTranslation();
@@ -76,6 +85,10 @@ const IncidentTable = ({
setRowsPerPage(event.target.value);
};
const handleResolveIncident = (checkId) => {
resolveIncident(checkId, setUpdateTrigger);
};
const headers = [
{
id: "monitorName",
@@ -114,9 +127,31 @@ const IncidentTable = ({
render: (row) => <HttpStatusLabel status={row.statusCode} />,
},
{ id: "message", content: t("incidentsTableMessage"), render: (row) => row.message },
{
id: "action",
content: t("actions"),
render: (row) => {
return row.ack === false ? (
<Button
variant="contained"
color="accent"
onClick={() => {
handleResolveIncident(row._id);
}}
>
{t("incidentsTableActionResolve")}
</Button>
) : (
<Typography>
{t("incidentsTableResolvedAt")}{" "}
{formatDateWithTz(row.ackAt, "YYYY-MM-DD HH:mm:ss A", uiTimezone)}
</Typography>
);
},
},
];
if (!shouldRender || isLoading) return <TableSkeleton />;
if (isLoading || resolveLoading) return <TableSkeleton />;
if (networkError) {
return (
@@ -149,10 +184,12 @@ const IncidentTable = ({
};
IncidentTable.propTypes = {
shouldRender: PropTypes.bool,
isLoading: PropTypes.bool,
monitors: PropTypes.object,
selectedMonitor: PropTypes.string,
filter: PropTypes.string,
dateRange: PropTypes.string,
updateTrigger: PropTypes.bool,
setUpdateTrigger: PropTypes.func,
};
export default IncidentTable;

View File

@@ -21,6 +21,12 @@ const OptionsHeader = ({
const theme = useTheme();
const { t } = useTranslation();
const monitorNames = typeof monitors !== "undefined" ? Object.values(monitors) : [];
const filterOptions = [
{ _id: "all", name: t("incidentsOptionsHeaderFilterAll") },
{ _id: "down", name: t("incidentsOptionsHeaderFilterDown") },
{ _id: "resolve", name: t("incidentsOptionsHeaderFilterCannotResolve") },
{ _id: "resolved", name: t("incidentsOptionsHeaderFilterResolved") },
];
// The stacks below which are three in number have the same style so
const stackStyles = {
@@ -65,36 +71,16 @@ const OptionsHeader = ({
>
{t("incidentsOptionsHeaderFilterBy")}
</Typography>
<ButtonGroup>
<Button
variant="group"
filled={(filter === "all").toString()}
onClick={() => setFilter("all")}
>
{t("incidentsOptionsHeaderFilterAll")}
</Button>
<Button
variant="group"
filled={(filter === "down").toString()}
onClick={() => setFilter("down")}
>
{t("incidentsOptionsHeaderFilterDown")}
</Button>
<Button
variant="group"
filled={(filter === "resolve").toString()}
onClick={() => setFilter("resolve")}
>
{t("incidentsOptionsHeaderFilterCannotResolve")}
</Button>
<Button
variant="group"
filled={(filter === "resolved").toString()}
onClick={() => setFilter("resolved")}
>
{t("incidentsOptionsHeaderFilterResolved")}
</Button>
</ButtonGroup>
<Select
id="incidents-select-filter"
value={filter}
onChange={(e) => setFilter(e.target.value)}
items={filterOptions}
sx={{
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastTextSecondary,
}}
/>
</Stack>
<Stack {...stackStyles}>
<Typography

View File

@@ -5,11 +5,13 @@ import GenericFallback from "../../Components/GenericFallback";
import IncidentTable from "./Components/IncidentTable";
import OptionsHeader from "./Components/OptionsHeader";
import StatusBoxes from "./Components/StatusBoxes";
import { Box, Button } from "@mui/material";
//Utils
import { useTheme } from "@emotion/react";
import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks";
import { useFetchChecksSummaryByTeamId } from "../../Hooks/checkHooks";
import { useAckAllChecks } from "../../Hooks/checkHooks";
import { useState, useEffect } from "react";
import NetworkError from "../../Components/GenericFallback/NetworkError";
import { useTranslation } from "react-i18next";
@@ -29,12 +31,17 @@ const Incidents = () => {
const [filter, setFilter] = useState(undefined);
const [dateRange, setDateRange] = useState(undefined);
const [monitorLookup, setMonitorLookup] = useState(undefined);
const [updateTrigger, setUpdateTrigger] = useState(false);
//Hooks
const [ackAllChecks, ackAllLoading] = useAckAllChecks();
//Utils
const theme = useTheme();
const [monitors, , isLoading, networkError] = useFetchMonitorsByTeamId({});
const [summary, isLoadingSummary, networkErrorSummary] =
useFetchChecksSummaryByTeamId();
const [summary, isLoadingSummary, networkErrorSummary] = useFetchChecksSummaryByTeamId({
updateTrigger,
});
const { monitorId } = useParams();
useEffect(() => {
@@ -55,6 +62,10 @@ const Incidents = () => {
setMonitorLookup(monitorLookup);
}, [monitors]);
const handleAckAllChecks = () => {
ackAllChecks(setUpdateTrigger);
};
if (networkError || networkErrorSummary) {
return (
<GenericFallback>
@@ -66,6 +77,16 @@ const Incidents = () => {
return (
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />
<Box alignSelf="flex-end">
<Button
variant="contained"
color="accent"
onClick={handleAckAllChecks}
disabled={ackAllLoading}
>
{t("incidentsPageActionResolve")}
</Button>
</Box>
<StatusBoxes
isLoading={isLoadingSummary}
summary={summary}
@@ -81,11 +102,13 @@ const Incidents = () => {
setDateRange={setDateRange}
/>
<IncidentTable
shouldRender={!isLoading}
isLoading={isLoading}
monitors={monitorLookup ? monitorLookup : {}}
selectedMonitor={selectedMonitor}
filter={filter}
dateRange={dateRange}
updateTrigger={updateTrigger}
setUpdateTrigger={setUpdateTrigger}
/>
</Stack>
);

View File

@@ -631,6 +631,12 @@ class NetworkService {
});
}
async updateAllChecksStatus(config) {
return this.axiosInstance.put(`/checks/team/`, {
ack: config.ack,
});
}
/**
* ************************************
* Get all checks for a given user

View File

@@ -390,7 +390,10 @@
"incidentsOptionsHeaderFilterBy": "Filter by:",
"incidentsOptionsHeaderTotalIncidents": "Total Incidents",
"incidentsOptionsHeaderFilterCannotResolve": "Cannot Resolve",
"incidentsTableResolvedAt": "Resolved at",
"incidentsOptionsHeaderFilterDown": "Down",
"incidentsTableActionResolve": "Resolve",
"incidentsPageActionResolve": "Resolve all incidents",
"incidentsOptionsHeaderFilterResolved": "Resolved",
"incidentsOptionsHeaderLastDay": "Last day",
"incidentsOptionsHeaderLastHour": "Last hour",
@@ -513,6 +516,10 @@
"monitorStatusUp": "Monitor {name} ({url}) is now UP and responding",
"monitors": "monitors",
"monitorsToApply": "Monitors to apply maintenance window to",
"checkHooks": {
"failureResolveOne": "Failed to resolve incident.",
"failureResolveAll": "Failed to resolve all incidents."
},
"ms": "ms",
"navControls": "Controls",
"nextWindow": "Next window",

View File

@@ -10,7 +10,11 @@ const buildChecksSummaryByTeamIdPipeline = ({ matchStage }) => {
totalChecks: { $sum: { $cond: [{ $eq: ["$status", false] }, 1, 0] } },
resolvedChecks: {
$sum: {
$cond: [{ $eq: ["$ack", true] }, 1, 0],
$cond: [
{ $and: [{ $eq: ["$ack", true] }, { $eq: ["$status", false] }] },
1,
0,
],
},
},
downChecks: {