Microsave

This commit is contained in:
Dunemask 2022-05-23 00:24:21 +00:00
parent 02c483950c
commit d94796173e
17 changed files with 735 additions and 228 deletions

View file

@ -11,22 +11,36 @@ export default function About() {
<div className="about">
<Container maxWidth="sm">
<Typography variant="h6" gutterBottom component="div">
<Box fontWeight='bold' display='inline'>Why?</Box>
</Typography>
<Typography variant="body1">
Qualiteer was designed to solve the issue of "on call". A state of being in which QA tests will fail, stiring everyone into a frenzy of what is broken in production! 🤯
Qualiteer gives users power to resolve and reattempt failing tests, run a particular suite of tests, and mute pesky alerts reminding you the navbar's color changed... 🤦
</Typography>
<br/>
<Typography variant="subtitle1" style={{ wordWrap: "break-word", whiteSpace:"normal" }}>
<Box fontWeight='bold' display='inline'>{"Repository: "} </Box>
<Link href={repoUrl} >{repoUrl}</Link>
</Typography>
<br/>
<div style={{justifyContent:"center", width:"100%", display:"flex"}}>
<Link href={memeUrl} variant="h6" underline="none">Qualiteer</Link>
</div>
</Container>
</div>
);
<Box fontWeight="bold" display="inline">
Why?
</Box>
</Typography>
<Typography variant="body1">
Qualiteer was designed to solve the issue of "on call". A state of
being in which QA tests will fail, stiring everyone into a frenzy of
what is broken in production! 🤯 Qualiteer gives users power to
resolve and reattempt failing tests, run a particular suite of tests,
and mute pesky alerts reminding you the navbar's color changed... 🤦
</Typography>
<br />
<Typography
variant="subtitle1"
style={{ wordWrap: "break-word", whiteSpace: "normal" }}
>
<Box fontWeight="bold" display="inline">
{"Repository: "}
</Box>
<Link href={repoUrl}>{repoUrl}</Link>
</Typography>
<br />
<div
style={{ justifyContent: "center", width: "100%", display: "flex" }}
>
<Link href={memeUrl} variant="h6" underline="none">
Qualiteer
</Link>
</div>
</Container>
</div>
);
}

View file

@ -1,16 +1,16 @@
import { useState, useContext } from "react";
import StoreContext from "../ctx/StoreContext.jsx";
import SpeedDial from '@mui/material/SpeedDial';
import SpeedDialAction from '@mui/material/SpeedDialAction';
import SpeedDialIcon from '@mui/material/SpeedDialIcon';
import SpeedDial from "@mui/material/SpeedDial";
import SpeedDialAction from "@mui/material/SpeedDialAction";
import SpeedDialIcon from "@mui/material/SpeedDialIcon";
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 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";
export default function Alerting() {
const { state: store, updateStore } = useContext(StoreContext);
@ -18,29 +18,23 @@ export default function Alerting() {
const [alertDialogOpen, setAlertDialogOpen] = useState(false);
const quickAlertClick = () => setAlertDialogOpen(!alertDialogOpen);
function silenceAlert(){
}
function silenceAlert() {}
const handleClose = (confirmed) => () => {
quickAlertClick();
if(!confirmed) return;
silenceAlert();
}
quickAlertClick();
if (!confirmed) return;
silenceAlert();
};
return (
<div className="alerting">
<Dialog
open={alertDialogOpen}
onClose={handleClose()}
sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }}
maxWidth="xs"
sx={{ "& .MuiDialog-paper": { width: "80%", maxHeight: 435 } }}
maxWidth="xs"
>
<DialogTitle>
Silence Alert
</DialogTitle>
<DialogContent>
</DialogContent>
<DialogTitle>Silence Alert</DialogTitle>
<DialogContent></DialogContent>
<DialogActions>
<Button onClick={handleClose()}>Cancel</Button>
<Button onClick={handleClose(true)} autoFocus>
@ -50,8 +44,8 @@ export default function Alerting() {
</Dialog>
<SpeedDial
ariaLabel="Silence Alert"
sx={{ position: 'absolute', bottom: 16, right: 16 }}
ariaLabel="Silence Alert"
sx={{ position: "fixed", bottom: 16, right: 16 }}
icon={<SpeedDialIcon />}
onClick={quickAlertClick}
open={false}

View file

@ -1,4 +1,4 @@
import { useContext } from "react";
import { useEffect, useContext } from "react";
import StoreContext from "../ctx/StoreContext.jsx";
import JobContext from "../ctx/JobContext.jsx";
@ -16,14 +16,25 @@ export default function Catalog() {
const { state: store, updateStore } = useContext(StoreContext);
const handleSearchChange = (e) =>
updateStore({ catalogSearch: e.target.value });
const handleSearchClear = () => updateStore({ catalogSearch: "" });
useEffect(() => {
return function unmount() {
handleSearchClear();
};
}, []);
return (
<div className="catalog">
<CatalogSearch />
<TextField
label="Search Catalog"
type="search"
variant="filled"
/>
<CatalogSearch
onChange={handleSearchChange}
onClear={handleSearchClear}
clearOnUnmount
/>
<h6>{store.catalogSearch}</h6>
</div>
);
}

View file

@ -2,48 +2,55 @@ import { useState, useContext } from "react";
import StoreContext from "../ctx/StoreContext.jsx";
import JobContext from "../ctx/JobContext.jsx";
import SpeedDial from '@mui/material/SpeedDial';
import SpeedDialAction from '@mui/material/SpeedDialAction';
import SpeedDialIcon from '@mui/material/SpeedDialIcon';
import SpeedDial from "@mui/material/SpeedDial";
import SpeedDialAction from "@mui/material/SpeedDialAction";
import SpeedDialIcon from "@mui/material/SpeedDialIcon";
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 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 ReplayIcon from "@mui/icons-material/Replay";
import FailingBox from "./components/FailingBox.jsx";
export default function Failing() {
const {
state: jobState,
retryAll
} = useContext(JobContext);
const { state: jobState, retryAll, activeJobStates } = useContext(JobContext);
const { state: store, updateStore } = useContext(StoreContext);
const { failing } = store;
/* TODO
for(var j of activeJobStates()){
const failingTest = failing.find((f)=>f.name===j.testName);
if(!failingTest) continue;
failingTest.jobStatus= j.status;
}*/
const [retryAllOpen, setRetryAllOpen] = useState(false);
const retryAllClick = () => setRetryAllOpen(!retryAllOpen);
const handleClose = (confirmed) => ()=> {
const handleClose = (confirmed) => () => {
retryAllClick();
if(!confirmed) return;
retryAll(store.failing);
}
if (!confirmed) return;
retryAll(store.failing);
};
return (
<div className="failing">
{failing.map((v, i) => (
<FailingBox key={i} failingTest={v} />
))}
<Dialog
open={retryAllOpen}
onClose={handleClose()}
sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }}
maxWidth="xs"
sx={{ "& .MuiDialog-paper": { width: "80%", maxHeight: 435 } }}
maxWidth="xs"
>
<DialogTitle>
Retry all failing tests?
</DialogTitle>
<DialogTitle>Retry all failing tests?</DialogTitle>
<DialogContent>
<DialogContentText>
This will create x jobs and run y tests
@ -56,15 +63,14 @@ export default function Failing() {
</Button>
</DialogActions>
</Dialog>
<SpeedDial
<SpeedDial
ariaLabel="Retry All"
sx={{ position: 'absolute', bottom: 16, right: 16 }}
sx={{ position: "fixed", bottom: 16, right: 16 }}
icon={<ReplayIcon />}
onClick={retryAllClick}
open={false}
open={false}
/>
</div>
);
}

View file

@ -2,15 +2,14 @@ import { useState, useContext } from "react";
import StoreContext from "../ctx/StoreContext.jsx";
import JobContext from "../ctx/JobContext.jsx";
import ClickAwayListener from "@mui/material/ClickAwayListener";
import SpeedDial from "@mui/material/SpeedDial";
import SpeedDialAction from "@mui/material/SpeedDialAction";
import SpeedDialIcon from "@mui/material/SpeedDialIcon";
import ClickAwayListener from '@mui/material/ClickAwayListener';
import SpeedDial from '@mui/material/SpeedDial';
import SpeedDialAction from '@mui/material/SpeedDialAction';
import SpeedDialIcon from '@mui/material/SpeedDialIcon';
import PageviewIcon from '@mui/icons-material/Pageview';
import ViewColumnIcon from '@mui/icons-material/ViewColumn';
import ViewCarouselIcon from '@mui/icons-material/ViewCarousel';
import PageviewIcon from "@mui/icons-material/Pageview";
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
import ViewCarouselIcon from "@mui/icons-material/ViewCarousel";
export default function Jobs() {
const {
@ -26,30 +25,32 @@ export default function Jobs() {
const quickOpenClick = () => setQuickOpen(!quickOpen);
const quickOpenClose = () => setQuickOpen(false);
const actions = [
{name: "Suite", icon: <ViewCarouselIcon/>}, {name: "Compound", icon: <ViewColumnIcon/>}, {name: "Manual", icon: <PageviewIcon/>}
]
{ name: "Suite", icon: <ViewCarouselIcon /> },
{ name: "Compound", icon: <ViewColumnIcon /> },
{ name: "Manual", icon: <PageviewIcon /> },
];
return (
<div className="jobs">
<ClickAwayListener onClickAway={quickOpenClose}>
<SpeedDial
ariaLabel="New Job"
sx={{ position: 'absolute', bottom: 16, right: 16 }}
icon={<SpeedDialIcon />}
onClick={quickOpenClick}
open={quickOpen}
>
{actions.map((action) => (
<SpeedDialAction
key={action.name}
icon={action.icon}
tooltipTitle={action.name}
/>
))}
</SpeedDial>
</ClickAwayListener>
<ClickAwayListener onClickAway={quickOpenClose}>
<SpeedDial
ariaLabel="New Job"
sx={{ position: "fixed", bottom: 16, right: 16 }}
icon={<SpeedDialIcon />}
onClick={quickOpenClick}
open={quickOpen}
>
{actions.map((action) => (
<SpeedDialAction
key={action.name}
icon={action.icon}
tooltipTitle={action.name}
/>
))}
</SpeedDial>
</ClickAwayListener>
</div>
);
}

View file

@ -1,76 +1,80 @@
import { useContext, useState, useEffect } from "react";
import React, { useContext, useState, useEffect } from "react";
import StoreContext from "../ctx/StoreContext.jsx";
import MultiOptionDialog from "./components/MultiOptionDialog.jsx";
import * as React from 'react';
import PropTypes from 'prop-types';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemText from '@mui/material/ListItemText';
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemText from "@mui/material/ListItemText";
import Switch from "@mui/material/Switch";
import SummarizeIcon from '@mui/icons-material/Summarize';
import SummarizeIcon from "@mui/icons-material/Summarize";
import Typography from "@mui/material/Typography";
export default function Settings(props) {
const { state: store, updateStore } = useContext(StoreContext);
const { regions } = store;
const { pages } = props;
const defaultDialog = {title: "", options: [], current: null, onSelect: null, open: false};
const [dialog, setDialog] = React.useState(defaultDialog);
const optionSettings = {region: {
title: "Region",
options: ["us", "au"],
current: store.defaultRegion,
onSelect: (r) => updateStore({defaultRegion: r})
},
defaultPage: {
title: "Default Page",
options: ["failing", "alerting"],
current: store.defaultPage,
onSelect: (p) => updateStore({defaultPage: p})
}}
const defaultDialog = {
title: "",
options: [],
current: null,
onSelect: null,
open: false,
};
const [dialog, setDialog] = useState(defaultDialog);
const optionSettings = {
region: {
title: "Region",
options: [],
current: store.defaultRegion,
onSelect: (r) => updateStore({ defaultRegion: r }),
},
defaultPage: {
title: "Default Page",
options: pages,
current: store.defaultPage,
onSelect: (p) => updateStore({ defaultPage: p }),
},
};
const handleOptionsMenu = (s) => {
setDialog({...s, open:true});
setDialog({ ...s, open: true });
};
const handleClose = (newValue, onSelect) => {
setDialog({...dialog, open:false})
setDialog({ ...dialog, open: false });
if (!newValue) return;
onSelect(newValue);
};
const handleToggle = (booleanSetting) => ()=> {
const handleToggle = (booleanSetting) => () => {
const storeUpdate = {};
storeUpdate[booleanSetting] = !store[booleanSetting];
updateStore(storeUpdate)
}
updateStore(storeUpdate);
};
function MultiOptionSubtext(props){
return( <React.Fragment>
<Typography
sx={{ display: 'inline' }}
component="span"
variant="body2"
color="primary"
>
{props.value}
</Typography>
</React.Fragment>)
function MultiOptionSubtext(props) {
return (
<React.Fragment>
<Typography
sx={{ display: "inline" }}
component="span"
variant="body2"
color="primary"
>
{props.value}
</Typography>
</React.Fragment>
);
}
return (
<Box sx={{ width: '100%', bgcolor: 'background.paper' }}>
<Box sx={{ width: "100%", bgcolor: "background.paper" }}>
<List component="div" role="group">
<ListItem
button
divider
@ -78,39 +82,48 @@ const defaultDialog = {title: "", options: [], current: null, onSelect: null, op
aria-label="default page"
onClick={() => handleOptionsMenu(optionSettings.defaultPage)}
>
<ListItemText primary="Default Page" secondary={
<MultiOptionSubtext value={optionSettings.defaultPage.current} />
}/>
<ListItemText
primary="Default Page"
secondary={
<MultiOptionSubtext value={optionSettings.defaultPage.current} />
}
/>
</ListItem>
<ListItem
<ListItem
button
divider
aria-haspopup="true"
aria-label="region"
onClick={() => handleOptionsMenu(optionSettings.region)}
disabled={optionSettings.region.options.length === 0}
>
<ListItemText primary="Region" secondary={<MultiOptionSubtext value={optionSettings.region.current} />} />
<ListItemText
primary="Region"
secondary={
<MultiOptionSubtext value={optionSettings.region.current} />
}
/>
</ListItem>
<ListItem button divider>
<ListItem button divider>
<ListItemText primary="Simplified Controls" />
<Switch
edge="end"
onChange={handleToggle("simplifiedControls")}
checked={store.simplifiedControls}
/>
<Switch
edge="end"
onChange={handleToggle("simplifiedControls")}
checked={store.simplifiedControls}
/>
</ListItem>
<ListItem button divider>
<ListItem button divider>
<ListItemText primary="Focus New Jobs" />
<Switch
edge="end"
onChange={handleToggle("focusJob")}
checked={store.focusJob}
/>
<Switch
edge="end"
onChange={handleToggle("focusJob")}
checked={store.focusJob}
/>
</ListItem>
<MultiOptionDialog
id="multi-options-menu"
keepMounted

View file

@ -0,0 +1,86 @@
import React, { useState, useContext } from "react";
import StoreContext from "../../ctx/StoreContext.jsx";
import JobContext from "../../ctx/JobContext.jsx";
import Accordion from "@mui/material/Accordion";
import AccordionDetails from "@mui/material/AccordionDetails";
import AccordionSummary from "@mui/material/AccordionSummary";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import DeleteIcon from "@mui/icons-material/Delete";
import NotificationsIcon from "@mui/icons-material/Notifications";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
export default function CatalogBox(props) {
const { catalogTest } = props;
const {
name: testName,
class: testClass,
repo: testRepo,
isCompound,
type: testType
} = catalogTest;
const { state: store, updateStore } = useContext(StoreContext);
const { state: jobState, jobBuilder} = useContext(JobContext);
const [open, setOpen] = useState(false);
const toggleOpen = () => setOpen(!open);
function Actions() {
return (
<React.Fragment>
<IconButton aria-label="play" component="span" color="primary">
<NotificationsIcon />
</IconButton>
<IconButton color="error" aria-label="delete" component="span">
<DeleteIcon />
</IconButton>
</React.Fragment>
);
}
return (
<Accordion expanded={open} disableGutters={true} onChange={toggleOpen}
square>
<AccordionSummary
style={{
backgroundColor: "rgba(0, 0, 0, .03)",
flexWrap: "wrap",
}}
>
<Typography component={"span"} style={{ wordBreak: "break-word" }}>
{`${testClass}#`}
<Box fontWeight="bold" display="inline">
{testName}
</Box>
<br />
</Typography>
<Stack
sx={{ ml: "auto", display: { md: "none", lg: "none", xl: "none" } }}
>
<Actions />
</Stack>
<Stack
direction="row"
sx={{
ml: "auto",
display: { xs: "none", sm: "none", md: "flex", lg: "flex" },
}}
>
<Actions />
</Stack>
<AccordionDetails>
<Typography>{JSON.stringify(catalogTest)}</Typography>
</AccordionDetails>
</AccordionSummary>
</Accordion>
);
}

View file

@ -1,31 +1,44 @@
import * as React from 'react';
import Paper from '@mui/material/Paper';
import InputBase from '@mui/material/InputBase';
import Divider from '@mui/material/Divider';
import IconButton from '@mui/material/IconButton';
import MenuIcon from '@mui/icons-material/Menu';
import SearchIcon from '@mui/icons-material/Search';
import DirectionsIcon from '@mui/icons-material/Directions';
import ClearOutlinedIcon from "@mui/icons-material/ClearOutlined";
import { useEffect, useRef } from "react";
import Paper from "@mui/material/Paper";
import InputBase from "@mui/material/InputBase";
import Divider from "@mui/material/Divider";
import IconButton from "@mui/material/IconButton";
import MenuIcon from "@mui/icons-material/Menu";
import SearchIcon from "@mui/icons-material/Search";
import DirectionsIcon from "@mui/icons-material/Directions";
import ClearOutlinedIcon from "@mui/icons-material/ClearOutlined";
export default function CatalogSearch(props) {
const { onChange, onClear } = props;
const searchRef = useRef(null);
const handleClear = () => {
searchRef.current.children[0].value = null;
searchRef.current.children[0].focus();
onClear();
};
export default function SearchBar(props) {
return (
<Paper
component="form"
sx={{ display: 'flex', alignItems: 'center'}}
>
<Paper component="form" sx={{ display: "flex", alignItems: "center" }}>
<InputBase
sx={{flex: 1 }}
ref={searchRef}
sx={{ ml: 1, flex: 1 }}
placeholder="Search Catalog"
inputProps={{ 'aria-label': `search catalog` }}
inputProps={{ "aria-label": `search catalog` }}
onChange={onChange}
/>
<IconButton type="submit" sx={{ p: '18px' }} aria-label="search">
<IconButton type="submit" sx={{ p: "10px" }} aria-label="search">
<SearchIcon />
</IconButton>
<Divider sx={{ height: 28, m: 0.5 }} orientation="vertical" />
<IconButton sx={{ p: '8px' }} aria-label="clear">
<Divider sx={{ height: 26, m: 0.5 }} orientation="vertical" />
<IconButton
sx={{ p: "10px", mr: 0.5 }}
aria-label="clear"
onClick={handleClear}
>
<ClearOutlinedIcon />
</IconButton>
</Paper>
);
}
}

View file

@ -0,0 +1,166 @@
import React, { useState, useContext } from "react";
import StoreContext from "../../ctx/StoreContext.jsx";
import JobContext, { jobStatus } from "../../ctx/JobContext.jsx";
import Accordion from "@mui/material/Accordion";
import AccordionDetails from "@mui/material/AccordionDetails";
import AccordionSummary from "@mui/material/AccordionSummary";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import DeleteIcon from "@mui/icons-material/Delete";
import NotificationsIcon from "@mui/icons-material/Notifications";
import ReplayIcon from "@mui/icons-material/Replay";
import PhotoCameraIcon from "@mui/icons-material/PhotoCamera";
import CheckIcon from "@mui/icons-material/Check";
import ClearIcon from "@mui/icons-material/Clear";
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
import PendingIcon from "@mui/icons-material/Pending";
import VisibilityIcon from "@mui/icons-material/Visibility";
import DoNotDisturbIcon from "@mui/icons-material/DoNotDisturb";
import Badge from "@mui/material/Badge";
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
const stopPropagation = (e) => e.stopPropagation() && e.preventDefault();
export default function FailingBox(props) {
const { failingTest } = props;
const {
class: testClass,
name: testName,
timestamp,
silencedUntil,
type,
dailyFails,
screenshot: screenshotUrl,
recentResults,
failedMessage,
isCompound,
jobStatus: testJobStatus,
} = failingTest;
const { state: jobState, retryTest, retryJobStatus } = useContext(JobContext);
const { state: store, updateStore } = useContext(StoreContext);
const [open, setOpen] = useState(false);
const toggleOpen = () => setOpen(!open);
function badgeColor() {
if (dailyFails === 1) return "primary";
else if (dailyFails === 2) return "secondary";
else if (dailyFails < 6) return "warning";
return "error";
}
function jobIcon() {
switch (testJobStatus) {
case jobStatus.OK:
return <CheckIcon color="success" />;
case jobStatus.ERROR:
return <ClearIcon color="error" />;
case jobStatus.PENDING:
return <PendingIcon color="info" />;
case jobStatus.ACTIVE:
return <VisibilityIcon color="primary" />;
case jobStatus.CANCELED:
return <DoNotDisturbIcon color="warning" />;
case jobStatus.QUEUED:
return <ViewColumnIcon color="secondary" />;
default:
return <ReplayIcon />;
}
}
function Actions() {
return (
<React.Fragment>
<IconButton aria-label="photo" component="span">
<PhotoCameraIcon />
</IconButton>
<IconButton aria-label="retry" component="span">
{jobIcon()}
</IconButton>
<IconButton
aria-label="silence"
component="span"
color={silencedUntil ? "primary" : "default"}
>
<NotificationsIcon />
</IconButton>
<IconButton color="error" aria-label="delete" component="span">
<DeleteIcon />
</IconButton>
</React.Fragment>
);
}
return (
<Accordion
expanded={open}
onChange={toggleOpen}
disableGutters={true}
square
>
<AccordionSummary
style={{
backgroundColor: "rgba(0, 0, 0, .03)",
flexWrap: "wrap",
}}
>
<Badge
sx={{ mr: 2 }}
color={badgeColor()}
badgeContent={dailyFails}
anchorOrigin={{
vertical: "top",
horizontal: "left",
}}
></Badge>
<Typography component={"span"} style={{ wordBreak: "break-word" }}>
{`${testClass}#`}
<Box fontWeight="bold" display="inline">
{testName}{" "}
</Box>
<br />
<span className="recent-results">
{recentResults.map(
(v, i) =>
(v && <CheckIcon key={i} color="success" />) || (
<ClearIcon key={i} color="error" />
)
)}
</span>
{isCompound && <ViewColumnIcon />}
</Typography>
<Stack
onClick={stopPropagation}
sx={{ ml: "auto", display: { md: "none", lg: "none", xl: "none" } }}
>
<Actions />
</Stack>
<Stack
onClick={stopPropagation}
direction="row"
sx={{
ml: "auto",
display: { xs: "none", sm: "none", md: "flex", lg: "flex" },
}}
>
<Actions />
</Stack>
</AccordionSummary>
<AccordionDetails>
<Typography>{failedMessage}</Typography>
</AccordionDetails>
</Accordion>
);
}

View file

@ -1,24 +1,22 @@
import {useState, useRef, useEffect} from "react";
import Button from "@mui/material/Button"
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import Dialog from '@mui/material/Dialog';
import RadioGroup from '@mui/material/RadioGroup';
import Radio from '@mui/material/Radio';
import FormControlLabel from '@mui/material/FormControlLabel';
import { useState, useRef, useEffect } from "react";
import Button from "@mui/material/Button";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import Dialog from "@mui/material/Dialog";
import RadioGroup from "@mui/material/RadioGroup";
import Radio from "@mui/material/Radio";
import FormControlLabel from "@mui/material/FormControlLabel";
export default function MultiOptionDialog(props) {
const { dialog: dialogProp, onClose, open, ...other } = props;
const [value, setValue] = useState(dialogProp.current);
const [dialog, setDialog] = useState(dialogProp);
const radioGroupRef = useRef(null);
useEffect(() => {
useEffect(() => {
setDialog(dialogProp);
setValue(dialogProp.current);
}, [dialogProp, open]);
@ -30,14 +28,14 @@ export default function MultiOptionDialog(props) {
const handleCancel = () => onClose();
const handleOk = () => onClose(value, dialog.onSelect);
const handleChange = (e) =>{ setValue(e.target.value);
}
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<Dialog
sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }}
sx={{ "& .MuiDialog-paper": { width: "80%", maxHeight: 435 } }}
maxWidth="xs"
TransitionProps={{ onEntering: handleEntering }}
open={open}

View file

@ -0,0 +1,47 @@
import { useState, useContext } from "react";
import StoreContext from "../../ctx/StoreContext.jsx";
import Button from "@mui/material/Button";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogActions from "@mui/material/DialogActions";
import Dialog from "@mui/material/Dialog";
export default function SilenceDialog(props) {
const { silence, open, onClose } = props;
const [silenceEntry, setSilenceEntry] = useState(silence);
useEffect(() => {
setSilenceEntry(silence);
}, [silence, open]);
const { state: store, updateStore } = useContext(StoreContext);
const upsertSilence = () => {
console.log("Would upsert silence", silenceEntry);
};
const handleCancel = () => onClose();
const handleOk = () => onClose(silenceEntry);
return (
<Dialog
sx={{ "& .MuiDialog-paper": { width: "80%", maxHeight: 435 } }}
maxWidth="xs"
open={open}
>
<DialogTitle>Silence Alert</DialogTitle>
<DialogContent>
<span>{JSON.stringify(silenceEntry)}</span>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleCancel}>
Cancel
</Button>
<Button onClick={handleOk}>Ok</Button>
</DialogActions>
</Dialog>
);
}

View file

@ -0,0 +1,75 @@
import React, { useState, useContext } from "react";
import StoreContext from "../../ctx/StoreContext.jsx";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import Typography from "@mui/material/Typography";
import IconButton from "@mui/material/IconButton";
import DeleteIcon from "@mui/icons-material/Delete";
import NotificationsIcon from "@mui/icons-material/Notifications";
import Stack from "@mui/material/Stack";
export default function SilencingBox(props) {
const { silenceEntry } = props;
const {
name: testName,
method: testMethod,
class: testClass,
id: silenceId,
silencedUntil,
} = silenceEntry;
const { state: store, updateStore } = useContext(StoreContext);
function Actions() {
return (
<React.Fragment>
<IconButton aria-label="modify" component="span" color="primary">
<NotificationsIcon />
</IconButton>
<IconButton color="error" aria-label="delete" component="span">
<DeleteIcon />
</IconButton>
</React.Fragment>
);
}
return (
<Accordion expanded={false} disableGutters={true} square>
<AccordionSummary
style={{
backgroundColor: "rgba(0, 0, 0, .03)",
flexWrap: "wrap",
}}
>
<Typography component={"span"} style={{ wordBreak: "break-word" }}>
{`Test Name: ${testName}`}
<br />
{`Method: ${testMethod}`}
<br />
{`Test Class: ${testClass}`}
<br />
{`Silenced Until: ${silencedUntil} Remaining Time: 2:50`}
</Typography>
<Stack
sx={{ ml: "auto", display: { md: "none", lg: "none", xl: "none" } }}
>
<Actions />
</Stack>
<Stack
direction="row"
sx={{
ml: "auto",
display: { xs: "none", sm: "none", md: "flex", lg: "flex" },
}}
>
<Actions />
</Stack>
</AccordionSummary>
</Accordion>
);
}