Skip to content

Commit

Permalink
repo cache cleanup (again)
Browse files Browse the repository at this point in the history
  • Loading branch information
moranbw committed Apr 1, 2022
1 parent 9a121ec commit 1ac77d0
Show file tree
Hide file tree
Showing 21 changed files with 2,201 additions and 0 deletions.
14 changes: 14 additions & 0 deletions client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Available Scripts

In the project directory, you can run:

### `npm run dev`

* Runs the app in the development mode.
* Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
* If speedtest-app's primary server is running, dev server will proxy requests to it.
* The page will reload if you make edits.<br>

### `npm run build`

* Builds the app for production to the `dist` folder.
13 changes: 13 additions & 0 deletions client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>speedtest</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
1,442 changes: 1,442 additions & 0 deletions client/package-lock.json

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "speedtest-app-client",
"version": "0.4.0",
"private": true,
"dependencies": {
"@fontsource/work-sans": "^4.5.7",
"@material-table/core": "^4.3.38",
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-swipeable-views": "^0.14.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^1.3.0",
"vite": "^2.9.1"
},
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
14 changes: 14 additions & 0 deletions client/src/components/app/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.App {
padding-top: 16px;
padding-bottom: 16px;
}

.logo {
max-height:50px;
padding-right: 10px;
}

.title {
padding-right: 20px;
}

158 changes: 158 additions & 0 deletions client/src/components/app/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { useState } from 'react';
import { MuiThemeProvider, createTheme } from '@material-ui/core/styles';
import { grey } from '@material-ui/core/colors';
import { AppBar, Box, CssBaseline, Tab, Tabs, Toolbar, Typography } from '@material-ui/core';
import PropTypes from "prop-types";
import SwipeableViews from 'react-swipeable-views';
import WorkSansWoff from "@fontsource/work-sans/files/work-sans-all-400-normal.woff"
import { StateProvider } from '../../state';
import BodyContent from "../body/BodyContent";
import train from "../../resources/train.png";
import './App.css';


function App() {
const [value, setValue] = useState(0);

const initialState =
{
ookla:
{
useServer: false,
serverJson: "",
server: "",
requestUrl: "ookla/test",
tableJson: "",
isLoading: false,
errorSnackbarOpen: false,
errorSnackbarMessage: "Request failed..."
},
iperf:
{
host: "",
port: "",
requestUrl: "iperf/test",
tableJson: "",
isLoading: false,
errorSnackbarOpen: false,
errorSnackbarMessage: "Request failed..."
},

}

const reducer = (state, newState) => {
// merge the old and new state
return { ...state, ...newState };
};

const workSans = {
fontFamily: 'Work Sans',
fontStyle: 'normal',
fontDisplay: 'swap',
fontWeight: 400,
src: `
local('Work Sans'),
url(${WorkSansWoff}) format('woff')
`,
unicodeRange:
'U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF',
};

const theme = createTheme({
palette: {
primary: { main: grey[300] },
secondary: { main: "#3b88c3" },
},
typography: {
fontFamily: 'Work Sans',
useNextVariants: true,
},
overrides: {
MuiCssBaseline: {
'@global': {
'@font-face': [workSans],
},
},
},
});

function TabPanel(props) {
const { children, value, index, ...other } = props;

return (
<Box
component="div"
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && { ...children }}
</Box>
);
}

TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};

const handleChange = (event, newValue) => {
setValue(newValue);
};

const handleChangeIndex = index => {
setValue(index);
};

function a11yProps(index) {
return {
id: `full-width-tab-${index}`,
'aria-controls': `full-width-tabpanel-${index}`,
};
}

return (
<MuiThemeProvider theme={theme}>
<CssBaseline>
<div className="App">
<AppBar position="static" color="primary">
<Toolbar>
<div><img className="logo" alt="logo" src={train} /></div>
<Typography className="title" variant="h6" color="inherit">
speedtest
</Typography>
<Tabs
value={value}
onChange={handleChange}
>
<Tab label="ookla" {...a11yProps(0)} />
<Tab label="iperf" {...a11yProps(1)} />
</Tabs>
</Toolbar>
</AppBar>
<SwipeableViews
axis={theme.direction === 'rtl' ? 'x-reverse' : 'x'}
index={value}
onChangeIndex={handleChangeIndex}
>
<StateProvider initialState={initialState.ookla} reducer={reducer} >
<TabPanel value={value} index={0} dir={theme.direction}>
<BodyContent requestMethod={"GET"} tab={"ookla"} />
</TabPanel>
</StateProvider>
<StateProvider initialState={initialState.iperf} reducer={reducer}>
<TabPanel value={value} index={1} dir={theme.direction}>
<BodyContent requestMethod={"POST"} tab={"iperf"} />
</TabPanel>
</StateProvider>
</SwipeableViews>
</div>
</CssBaseline>
</MuiThemeProvider>
);

}
export default App;
9 changes: 9 additions & 0 deletions client/src/components/app/App.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});
4 changes: 4 additions & 0 deletions client/src/components/body/BodyContent.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
div.MuiSnackbar-root {
position: relative;
bottom: 0%;
}
106 changes: 106 additions & 0 deletions client/src/components/body/BodyContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { Container, Grid, LinearProgress, Paper, Snackbar } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { useStateValue } from '../../state';
import OoklaForm from "../ookla/OoklaForm";
import OoklaTable from "../ookla/OoklaTable";
import IperfForm from "../iperf/IperfForm";
import IperfTable from "../iperf/IperfTable";
import ConnectionSnackbarContent from "../snackbar/ConnectionSnackbarContent";
import catchFetch from '../../util/catchFetch';

import "./BodyContent.css"

const useStyles = makeStyles(theme => ({
root: {
padding: 16,
margin: 16,
backgroundColor: theme.palette.primary.main,
},
progress: {
width: '100%',
'& > * + *': {
marginTop: theme.spacing(2),
},
},

}));

export default function BodyContent(props) {
const classes = useStyles();
const [state, setState] = useStateValue();

const ConditionalResult = (props) => {
const tableJson = props.tableJson;
if (tableJson.length > 0) {
return <Grid item xs={12}>{props.tab === "ookla" ?
<OoklaTable json={state.tableJson} /> : <IperfTable json={state.tableJson} />}</Grid>;
}
return null;
};

const ConditionalLoad = (props) => {
if (state.isLoading) {
return <Grid item xs={12} className={classes.progress}><LinearProgress color="secondary" /></Grid>;
}
return props.tab === "ookla" ?
<OoklaForm onClick={onClick} /> : <IperfForm onClick={onClick} />;
};

const onClick = (aState) => {
let options = {
method: props.requestMethod
};
if (props.tab === "iperf") {
setState({ host: aState.host, port: aState.port, isLoading: true, tableJson: "" });
options.body = JSON.stringify({ host: aState.host, port: aState.port });
options.headers = {
'Content-Type': 'application/json'
};
options.mode = 'cors'; // no-cors, cors, *same-origin
options.credentials = 'same-origin'; // include, *same-origin, omit
}
else {
setState({ isLoading: true, tableJson: "" });

}
catchFetch(state.requestUrl, options)
.then((aResponse) => {
return aResponse.json();
})
.then((aJson) => {
console.log(aJson);
setState({ isLoading: false, tableJson: JSON.stringify(aJson) });
})
.catch((aError) => {
console.log(aError.message);
setState({
isLoading: false,
tableJson: "",
errorSnackbarOpen: true,
errorSnackbarMessage: "Request rejected, " + aError.response.status + ": " + aError.response.statusText
});
});
};

const closeSnackBar = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setState( { errorSnackbarOpen: false });
};

return (
<Container fixed>
<Paper className={classes.root} elevation={10}>
<Grid container direction="column" justifyContent="center" alignItems="center" spacing={4}>
<ConditionalResult tableJson={state.tableJson} tab={props.tab} />
<ConditionalLoad isLoading={state.isLoading} tab={props.tab} />
</Grid>
</Paper>
<Snackbar open={state.errorSnackbarOpen} autoHideDuration={6000} onClose={closeSnackBar}>
<ConnectionSnackbarContent message={state.errorSnackbarMessage} variant={"error"}
onClose={closeSnackBar} />
</Snackbar>
</Container>
);
}
Loading

0 comments on commit 1ac77d0

Please sign in to comment.