qualiteer/src/views/failing/Failing.jsx

135 lines
4.3 KiB
JavaScript

import { useState, useContext } from "react";
import { useCurrentlyFailing, useSilencedAlerts } from "@qltr/queries";
import StoreContext from "@qltr/store";
import JobContext from "@qltr/jobs";
import { useJobNav } from "@qltr/util/JobTools";
import SilenceDialog from "../alerting/SilenceDialog.jsx";
import FailingBox from "./FailingBox.jsx";
import SpeedDial from "@mui/material/SpeedDial";
import Button from "@mui/material/Button";
import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogTitle from "@mui/material/DialogTitle";
import ReplayIcon from "@mui/icons-material/Replay";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
export default function Failing() {
const { state: jobState, retryAll } = useContext(JobContext);
const { state: store, silenceRequest } = useContext(StoreContext);
const { isLoading, data: failing } = useCurrentlyFailing();
const { isSilencedLoading, data: silencedAlerts } = useSilencedAlerts();
const jobNav = useJobNav();
const [silenceEntry, setSilenceEntry] = useState({ open: false });
const closeSilence = () => setSilenceEntry({ ...silenceEntry, open: false });
const handleSilenceClose = (silenceReq) => {
closeSilence();
if (!silenceReq) return;
silenceRequest(silenceReq);
};
const editSilence = (silence) => () => {
setSilenceEntry({ ...silence, open: true });
};
const [retryAllOpen, setRetryAllOpen] = useState(false);
const retryAllClick = () => setRetryAllOpen(!retryAllOpen);
const handleClose = (confirmed) => () => {
retryAllClick();
if (!confirmed) return;
const jobId = retryAll(store.failing);
if (!store.focusJob) return;
jobNav.toJob(jobId);
};
const failingTestsWithJobs = () => {
if (isLoading) return [];
const silences = silencedAlerts ?? [];
for (var test of failing) {
const silence = silences.find(
(s) => s.name === test.name || s.class === test.class
);
if (silence) test.silencedUntil = silence;
if (test.isPipeline) {
const pipeline = jobState.pipelines.find((p) =>
p.selectedBranches.find((b) => b.name === test.name)
);
if (!pipeline) continue;
const pipelineJob = jobState.jobs.find(
(j) =>
j.isPipeline &&
j.pipelineId === pipeline.id &&
j.branchId === test.name
);
if (!pipelineJob) test.pipeline = pipeline;
test.job = pipelineJob;
continue;
}
const job = jobState.jobs.find(
(j) => !j.isPipeline && j.builderCache.testNames.includes(test.name)
);
if (job) test.job = job;
}
return failing;
};
return (
<div className="failing">
{isLoading
? null
: failingTestsWithJobs().map((v, i) => (
<FailingBox key={i} failingTest={v} silenceClick={editSilence(v)} />
))}
<Dialog
open={retryAllOpen}
onClose={handleClose()}
sx={{ "& .MuiDialog-paper": { width: "80%", maxHeight: 435 } }}
maxWidth="xs"
>
<DialogTitle>Retry all failing tests?</DialogTitle>
<DialogContent>
<DialogContentText>
This will create x jobs and run y tests
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose()}>Cancel</Button>
<Button onClick={handleClose(true)} autoFocus>
Yes
</Button>
</DialogActions>
</Dialog>
<SilenceDialog
keepMounted
open={silenceEntry.open}
onClose={handleSilenceClose}
silence={silenceEntry}
/>
{(failing ?? []).length === 0 ? (
<Box display="flex" alignItems="center" justifyContent="center">
<Typography variant="h4">No tests failing!</Typography>
</Box>
) : null}
{(failing ?? []).length === 0 ? null : (
<SpeedDial
ariaLabel="Retry All"
sx={{ position: "fixed", bottom: 16, right: 16 }}
icon={<ReplayIcon />}
onClick={retryAllClick}
open={false}
/>
)}
</div>
);
}