-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Task 1 and Task 2 of GSOC'21 WebUI challenge completed #14
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
|
||
import { exec } from '../util/exec'; | ||
|
||
import Chart from 'react-google-charts'; | ||
|
||
const CameraLoadWidget = props => { | ||
const [load, setLoad] = useState([ | ||
['Time Lapsed(In seconds)', '1 minute avg', '5 minute avg', '15 minute avg'], | ||
[0, 0, 0, 0], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding these makes all of the graphs start from zero, even if the load never was zero. |
||
]); | ||
useEffect(() => { | ||
rroohhh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let intervalId = setInterval(function a() { | ||
exec('uptime').then(result => { | ||
let splitres = String(result) | ||
.trim() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this first |
||
.split('load average:')[1] | ||
.trim() | ||
.split(','); | ||
|
||
setLoad(oldLoad => { | ||
let loadArr = [ | ||
[ | ||
oldLoad[oldLoad.length - 1][0] + 1, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably use the actual time as included from the |
||
splitres[0].trim(), | ||
splitres[1].trim(), | ||
splitres[2].trim(), | ||
], | ||
]; | ||
return oldLoad.concat(loadArr); | ||
}); | ||
}); | ||
}, 1000); | ||
|
||
return () => { | ||
clearInterval(intervalId); | ||
}; | ||
}, []); | ||
|
||
return ( | ||
<p> | ||
<Chart height={'400px'} chartType="Line" data={load} /> | ||
</p> | ||
); | ||
}; | ||
|
||
export default CameraLoadWidget; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,311 @@ | ||
import React from 'react'; | ||
import { useState } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { makeStyles } from '@material-ui/core/styles'; | ||
import Table from '@material-ui/core/Table'; | ||
import TableBody from '@material-ui/core/TableBody'; | ||
import TableCell from '@material-ui/core/TableCell'; | ||
import TableContainer from '@material-ui/core/TableContainer'; | ||
import TableHead from '@material-ui/core/TableHead'; | ||
import TableRow from '@material-ui/core/TableRow'; | ||
import TablePagination from '@material-ui/core/TablePagination'; | ||
import TableSortLabel from '@material-ui/core/TableSortLabel'; | ||
import Toolbar from '@material-ui/core/Toolbar'; | ||
import Typography from '@material-ui/core/Typography'; | ||
import Paper from '@material-ui/core/Paper'; | ||
import { Box, Chip } from '@material-ui/core'; | ||
import IconButton from '@material-ui/core/IconButton'; | ||
import FirstPageIcon from '@material-ui/icons/FirstPage'; | ||
import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft'; | ||
import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight'; | ||
import LastPageIcon from '@material-ui/icons/LastPage'; | ||
import { useTheme } from '@material-ui/core/styles'; | ||
|
||
const headCells = [ | ||
{ id: 'SSID', numeric: false, disablePadding: false, label: 'SSID' }, | ||
{ id: 'MODE', numeric: false, disablePadding: false, label: 'MODE' }, | ||
{ id: 'CHAN', numeric: true, disablePadding: false, label: 'CHAN' }, | ||
{ id: 'RATE', numeric: true, disablePadding: false, label: 'RATE' }, | ||
{ id: 'SIGNAL', numeric: true, disablePadding: false, label: 'SIGNAL' }, | ||
|
||
{ id: 'SECURITY', numeric: false, disablePadding: false, label: 'SECURITY' }, | ||
]; | ||
|
||
function EnhancedTableHead(props) { | ||
const { classes, order, orderBy, onRequestSort } = props; | ||
|
||
return ( | ||
<TableHead> | ||
<TableRow> | ||
{headCells.map(headCell => { | ||
return ( | ||
<TableCell | ||
key={headCell.id} | ||
align="center" | ||
padding={headCell.disablePadding ? 'none' : 'default'} | ||
sortDirection={orderBy === headCell.id ? order : false} | ||
> | ||
<TableSortLabel | ||
active={orderBy === headCell.id} | ||
direction={orderBy === headCell.id ? order : 'asc'} | ||
onClick={event => { | ||
onRequestSort(event, headCell.id); | ||
}} | ||
> | ||
<b>{headCell.label}</b> | ||
{orderBy === headCell.id ? ( | ||
<span className={classes.visuallyHidden}> | ||
{order === 'desc' ? 'sorted descending' : 'sorted ascending'} | ||
</span> | ||
) : null} | ||
</TableSortLabel> | ||
</TableCell> | ||
); | ||
})} | ||
</TableRow> | ||
</TableHead> | ||
); | ||
} | ||
|
||
EnhancedTableHead.propTypes = { | ||
classes: PropTypes.object.isRequired, | ||
onRequestSort: PropTypes.func.isRequired, | ||
order: PropTypes.oneOf(['asc', 'desc']).isRequired, | ||
orderBy: PropTypes.string.isRequired, | ||
}; | ||
|
||
const EnhancedTableToolbar = () => { | ||
return ( | ||
<Box> | ||
<Toolbar> | ||
<Typography variant="h5" id="tableTitle" component="span"> | ||
Wifi Networks | ||
</Typography> | ||
</Toolbar> | ||
</Box> | ||
); | ||
}; | ||
|
||
const useStyles = makeStyles(theme => ({ | ||
root: { | ||
width: '90%', | ||
margin: theme.spacing(2), | ||
}, | ||
paper: { | ||
width: '100%', | ||
padding: theme.spacing(2), | ||
marginBottom: theme.spacing(1), | ||
}, | ||
table: { | ||
minWidth: 550, | ||
}, | ||
visuallyHidden: { | ||
border: 0, | ||
clip: 'rect(0 0 0 0)', | ||
height: 1, | ||
margin: -1, | ||
overflow: 'hidden', | ||
padding: 0, | ||
position: 'absolute', | ||
top: 20, | ||
width: 1, | ||
}, | ||
chips: { | ||
display: 'flex', | ||
justifyContent: 'left', | ||
flexWrap: 'wrap', | ||
'& > *': { | ||
margin: theme.spacing(0.2), | ||
}, | ||
}, | ||
})); | ||
|
||
function descendingComparator(a, b, orderBy) { | ||
let isNumeric = false; | ||
headCells.forEach(obj => { | ||
if (obj.id == orderBy) { | ||
isNumeric = obj.numeric; | ||
} | ||
}); | ||
const v1 = isNumeric ? parseInt(a[orderBy]) : a[orderBy]; | ||
const v2 = isNumeric ? parseInt(b[orderBy]) : b[orderBy]; | ||
|
||
if (v2 < v1) { | ||
return -1; | ||
} | ||
if (v2 > v1) { | ||
return 1; | ||
} | ||
return 0; | ||
} | ||
|
||
function getComparator(order, orderBy) { | ||
return order === 'desc' | ||
? (a, b) => descendingComparator(a, b, orderBy) | ||
: (a, b) => -descendingComparator(a, b, orderBy); | ||
} | ||
|
||
function stableSort(array, comparator) { | ||
const stabilizedThis = array.map((el, index) => [el, index]); | ||
stabilizedThis.sort((a, b) => { | ||
const order = comparator(a[0], b[0]); | ||
if (order !== 0) return order; | ||
return a[1] - b[1]; | ||
}); | ||
return stabilizedThis.map(el => el[0]); | ||
} | ||
|
||
const useStyles1 = makeStyles(theme => ({ | ||
root: { | ||
flexShrink: 0, | ||
marginLeft: theme.spacing(2.5), | ||
}, | ||
})); | ||
|
||
function TablePaginationActions(props) { | ||
const classes = useStyles1(); | ||
const theme = useTheme(); | ||
const { count, page, rowsPerPage, onChangePage } = props; | ||
|
||
const handleFirstPageButtonClick = event => { | ||
onChangePage(event, 0); | ||
}; | ||
|
||
const handleBackButtonClick = event => { | ||
onChangePage(event, page - 1); | ||
}; | ||
|
||
const handleNextButtonClick = event => { | ||
onChangePage(event, page + 1); | ||
}; | ||
|
||
const handleLastPageButtonClick = event => { | ||
onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1)); | ||
}; | ||
|
||
return ( | ||
<div className={classes.root}> | ||
<IconButton | ||
onClick={handleFirstPageButtonClick} | ||
disabled={page === 0} | ||
aria-label="first page" | ||
> | ||
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />} | ||
</IconButton> | ||
<IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page"> | ||
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />} | ||
</IconButton> | ||
<IconButton | ||
onClick={handleNextButtonClick} | ||
disabled={page >= Math.ceil(count / rowsPerPage) - 1} | ||
aria-label="next page" | ||
> | ||
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />} | ||
</IconButton> | ||
<IconButton | ||
onClick={handleLastPageButtonClick} | ||
disabled={page >= Math.ceil(count / rowsPerPage) - 1} | ||
aria-label="last page" | ||
> | ||
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />} | ||
</IconButton> | ||
</div> | ||
); | ||
} | ||
|
||
TablePaginationActions.propTypes = { | ||
count: PropTypes.number.isRequired, | ||
onChangePage: PropTypes.func.isRequired, | ||
page: PropTypes.number.isRequired, | ||
rowsPerPage: PropTypes.number.isRequired, | ||
}; | ||
|
||
export default function EnhancedTable(props) { | ||
const classes = useStyles(); | ||
const [order, setOrder] = useState('asc'); | ||
const [orderBy, setOrderBy] = useState('SSID'); | ||
const [page, setPage] = React.useState(0); | ||
|
||
const [rowsPerPage, setRowsPerPage] = React.useState(5); | ||
const { rows } = props; | ||
|
||
const handleRequestSort = (event, property) => { | ||
const isAsc = orderBy === property && order === 'asc'; | ||
setOrder(isAsc ? 'desc' : 'asc'); | ||
setOrderBy(property); | ||
}; | ||
|
||
const handleChangePage = (event, newPage) => { | ||
setPage(newPage); | ||
}; | ||
|
||
const handleChangeRowsPerPage = event => { | ||
setRowsPerPage(parseInt(event.target.value, 10)); | ||
setPage(0); | ||
}; | ||
|
||
const theme = useTheme(); | ||
|
||
return ( | ||
<div className={classes.root}> | ||
<Paper className={classes.paper}> | ||
<EnhancedTableToolbar /> | ||
<TableContainer> | ||
<Table className={classes.table} aria-labelledby="tableTitle" aria-label="sortable table"> | ||
<EnhancedTableHead | ||
classes={classes} | ||
order={order} | ||
orderBy={orderBy} | ||
onRequestSort={handleRequestSort} | ||
/> | ||
<TableBody> | ||
{stableSort(rows, getComparator(order, orderBy)) | ||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) | ||
.map((row, index) => { | ||
return ( | ||
<TableRow tabIndex={-1} key={index}> | ||
<TableCell | ||
align="center" | ||
style={{ color: row['IN-USE'] != '' ? 'red' : 'black' }} | ||
> | ||
{row['SSID']} | ||
</TableCell> | ||
<TableCell align="center">{row['MODE']}</TableCell> | ||
<TableCell align="center">{row['CHAN']}</TableCell> | ||
<TableCell align="center">{row['RATE']}</TableCell> | ||
<TableCell align="center">{row['SIGNAL']}</TableCell> | ||
<TableCell align="center"> | ||
{' '} | ||
{row['SECURITY'].split(' ').map(tag => { | ||
return ( | ||
<Chip | ||
key={tag} | ||
label={tag} | ||
variant="outlined" | ||
style={{ margin: '2px' }} | ||
/> | ||
); | ||
})} | ||
</TableCell> | ||
</TableRow> | ||
); | ||
})} | ||
</TableBody> | ||
</Table> | ||
</TableContainer> | ||
|
||
<TablePagination | ||
style={{ marginRight: '1px' }} | ||
rowsPerPageOptions={[5, 10, 25]} | ||
component="div" | ||
count={rows.length} | ||
rowsPerPage={rowsPerPage} | ||
page={page} | ||
onChangePage={handleChangePage} | ||
onChangeRowsPerPage={handleChangeRowsPerPage} | ||
ActionsComponent={TablePaginationActions} | ||
/> | ||
</Paper> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,17 @@ | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta | ||
name="viewport" | ||
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" | ||
/> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | ||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | ||
<title>AXIOM-web</title> | ||
</head> | ||
|
||
</head> | ||
|
||
<body style="margin: 0; padding: 0; overflow-x: hidden;"> | ||
<div id="root"></div> | ||
<script src="index.jsx"></script> | ||
</body> | ||
|
||
</html> | ||
<body style="margin: 0; padding: 0; overflow-x: hidden;"> | ||
<div id="root"></div> | ||
<script src="index.jsx"></script> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This package seems to load a script from the internet, unfortunately this doesn't really work for this application, as this site has to work without internet access.