Savepoint

This commit is contained in:
Dunemask 2022-05-17 12:32:04 +00:00
parent 7db1a3456b
commit 02c483950c
45 changed files with 5136 additions and 256 deletions

32
src/views/About.jsx Normal file
View file

@ -0,0 +1,32 @@
import Typography from "@mui/material/Typography";
import Link from "@mui/material/Link";
import Container from "@mui/material/Container";
import Box from "@mui/material/Box";
const memeUrl = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";
const repoUrl = "https://gitlab.com/dunemask/Qualiteer";
export default function About() {
return (
<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>
);
}

61
src/views/Alerting.jsx Normal file
View file

@ -0,0 +1,61 @@
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 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);
const [alertDialogOpen, setAlertDialogOpen] = useState(false);
const quickAlertClick = () => setAlertDialogOpen(!alertDialogOpen);
function silenceAlert(){
}
const handleClose = (confirmed) => () => {
quickAlertClick();
if(!confirmed) return;
silenceAlert();
}
return (
<div className="alerting">
<Dialog
open={alertDialogOpen}
onClose={handleClose()}
sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }}
maxWidth="xs"
>
<DialogTitle>
Silence Alert
</DialogTitle>
<DialogContent>
</DialogContent>
<DialogActions>
<Button onClick={handleClose()}>Cancel</Button>
<Button onClick={handleClose(true)} autoFocus>
Silence
</Button>
</DialogActions>
</Dialog>
<SpeedDial
ariaLabel="Silence Alert"
sx={{ position: 'absolute', bottom: 16, right: 16 }}
icon={<SpeedDialIcon />}
onClick={quickAlertClick}
open={false}
/>
</div>
);
}

29
src/views/Catalog.jsx Normal file
View file

@ -0,0 +1,29 @@
import { useContext } from "react";
import StoreContext from "../ctx/StoreContext.jsx";
import JobContext from "../ctx/JobContext.jsx";
import TextField from "@mui/material/TextField";
import CatalogSearch from "./components/CatalogSearch.jsx";
export default function Catalog() {
const {
state: jobState,
dispatch: jobDispatch,
jobUpdate,
jobCreate,
} = useContext(JobContext);
const { state: store, updateStore } = useContext(StoreContext);
return (
<div className="catalog">
<CatalogSearch />
<TextField
label="Search Catalog"
type="search"
variant="filled"
/>
</div>
);
}

70
src/views/Failing.jsx Normal file
View file

@ -0,0 +1,70 @@
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 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';
export default function Failing() {
const {
state: jobState,
retryAll
} = useContext(JobContext);
const { state: store, updateStore } = useContext(StoreContext);
const [retryAllOpen, setRetryAllOpen] = useState(false);
const retryAllClick = () => setRetryAllOpen(!retryAllOpen);
const handleClose = (confirmed) => ()=> {
retryAllClick();
if(!confirmed) return;
retryAll(store.failing);
}
return (
<div className="failing">
<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>
<SpeedDial
ariaLabel="Retry All"
sx={{ position: 'absolute', bottom: 16, right: 16 }}
icon={<ReplayIcon />}
onClick={retryAllClick}
open={false}
/>
</div>
);
}

55
src/views/Jobs.jsx Normal file
View file

@ -0,0 +1,55 @@
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 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 {
state: jobState,
dispatch: jobDispatch,
jobUpdate,
jobCreate,
} = useContext(JobContext);
const { state: store, updateStore } = useContext(StoreContext);
const [quickOpen, setQuickOpen] = useState(false);
const quickOpenClick = () => setQuickOpen(!quickOpen);
const quickOpenClose = () => setQuickOpen(false);
const actions = [
{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>
</div>
);
}

124
src/views/Settings.jsx Normal file
View file

@ -0,0 +1,124 @@
import { 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 Switch from "@mui/material/Switch";
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 handleOptionsMenu = (s) => {
setDialog({...s, open:true});
};
const handleClose = (newValue, onSelect) => {
setDialog({...dialog, open:false})
if (!newValue) return;
onSelect(newValue);
};
const handleToggle = (booleanSetting) => ()=> {
const storeUpdate = {};
storeUpdate[booleanSetting] = !store[booleanSetting];
updateStore(storeUpdate)
}
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' }}>
<List component="div" role="group">
<ListItem
button
divider
aria-haspopup="true"
aria-label="default page"
onClick={() => handleOptionsMenu(optionSettings.defaultPage)}
>
<ListItemText primary="Default Page" secondary={
<MultiOptionSubtext value={optionSettings.defaultPage.current} />
}/>
</ListItem>
<ListItem
button
divider
aria-haspopup="true"
aria-label="region"
onClick={() => handleOptionsMenu(optionSettings.region)}
>
<ListItemText primary="Region" secondary={<MultiOptionSubtext value={optionSettings.region.current} />} />
</ListItem>
<ListItem button divider>
<ListItemText primary="Simplified Controls" />
<Switch
edge="end"
onChange={handleToggle("simplifiedControls")}
checked={store.simplifiedControls}
/>
</ListItem>
<ListItem button divider>
<ListItemText primary="Focus New Jobs" />
<Switch
edge="end"
onChange={handleToggle("focusJob")}
checked={store.focusJob}
/>
</ListItem>
<MultiOptionDialog
id="multi-options-menu"
keepMounted
open={dialog.open}
onClose={handleClose}
dialog={dialog}
/>
</List>
</Box>
);
}

View file

@ -0,0 +1,31 @@
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";
export default function SearchBar(props) {
return (
<Paper
component="form"
sx={{ display: 'flex', alignItems: 'center'}}
>
<InputBase
sx={{flex: 1 }}
placeholder="Search Catalog"
inputProps={{ 'aria-label': `search catalog` }}
/>
<IconButton type="submit" sx={{ p: '18px' }} aria-label="search">
<SearchIcon />
</IconButton>
<Divider sx={{ height: 28, m: 0.5 }} orientation="vertical" />
<IconButton sx={{ p: '8px' }} aria-label="clear">
<ClearOutlinedIcon />
</IconButton>
</Paper>
);
}

View file

@ -0,0 +1,73 @@
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(() => {
setDialog(dialogProp);
setValue(dialogProp.current);
}, [dialogProp, open]);
const handleEntering = () => {
if (radioGroupRef.current != null) radioGroupRef.current.focus();
};
const handleCancel = () => onClose();
const handleOk = () => onClose(value, dialog.onSelect);
const handleChange = (e) =>{ setValue(e.target.value);
}
return (
<Dialog
sx={{ '& .MuiDialog-paper': { width: '80%', maxHeight: 435 } }}
maxWidth="xs"
TransitionProps={{ onEntering: handleEntering }}
open={open}
{...other}
>
<DialogTitle>{dialog.title}</DialogTitle>
<DialogContent dividers>
<RadioGroup
ref={radioGroupRef}
aria-label={dialogProp.title}
name={dialog.title}
value={value}
onChange={handleChange}
>
{dialog.options.map((option) => (
<FormControlLabel
value={option}
key={option}
control={<Radio />}
label={option}
/>
))}
</RadioGroup>
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleCancel}>
Cancel
</Button>
<Button onClick={handleOk}>Ok</Button>
</DialogActions>
</Dialog>
);
}