WIP - demo project

This commit is contained in:
Rick Watson 2019-07-06 23:56:30 +01:00
parent 4bb4871a6d
commit a0d6524180
17 changed files with 250 additions and 20 deletions

View File

@ -1 +1,5 @@
REACT_APP_NAME=ESP8266 React # This is the name of your project. It appears on the sign-in page and in the menu bar.
REACT_APP_PROJECT_NAME=ESP8266 React
# This is the url path your project will be exposed under.
REACT_APP_PROJECT_PATH=project

View File

@ -1 +1 @@
REACT_APP_ENDPOINT_ROOT=http://192.168.0.11/rest/ REACT_APP_ENDPOINT_ROOT=http://192.168.0.19/rest/

View File

@ -2,18 +2,18 @@ import React, { Component } from 'react';
import { Redirect, Switch } from 'react-router'; import { Redirect, Switch } from 'react-router';
import { PROJECT_PATH } from './constants/Env';
import * as Authentication from './authentication/Authentication'; import * as Authentication from './authentication/Authentication';
import AuthenticationWrapper from './authentication/AuthenticationWrapper'; import AuthenticationWrapper from './authentication/AuthenticationWrapper';
import AuthenticatedRoute from './authentication/AuthenticatedRoute'; import AuthenticatedRoute from './authentication/AuthenticatedRoute';
import UnauthenticatedRoute from './authentication/UnauthenticatedRoute'; import UnauthenticatedRoute from './authentication/UnauthenticatedRoute';
import SignInPage from './containers/SignInPage'; import SignInPage from './containers/SignInPage';
import WiFiConnection from './sections/WiFiConnection'; import WiFiConnection from './sections/WiFiConnection';
import AccessPoint from './sections/AccessPoint'; import AccessPoint from './sections/AccessPoint';
import NetworkTime from './sections/NetworkTime'; import NetworkTime from './sections/NetworkTime';
import Security from './sections/Security'; import Security from './sections/Security';
import System from './sections/System'; import System from './sections/System';
import ProjectRouting from './project/ProjectRouting';
class AppRouting extends Component { class AppRouting extends Component {
@ -31,6 +31,7 @@ class AppRouting extends Component {
<AuthenticatedRoute exact path="/ntp/*" component={NetworkTime} /> <AuthenticatedRoute exact path="/ntp/*" component={NetworkTime} />
<AuthenticatedRoute exact path="/security/*" component={Security} /> <AuthenticatedRoute exact path="/security/*" component={Security} />
<AuthenticatedRoute exact path="/system/*" component={System} /> <AuthenticatedRoute exact path="/system/*" component={System} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/*`} component={ProjectRouting} />
<Redirect to="/" /> <Redirect to="/" />
</Switch> </Switch>
</AuthenticationWrapper> </AuthenticationWrapper>

View File

@ -1,4 +1,5 @@
import history from '../history'; import history from '../history';
import { PROJECT_PATH } from '../constants/Env';
export const ACCESS_TOKEN = 'access_token'; export const ACCESS_TOKEN = 'access_token';
export const LOGIN_PATHNAME = 'loginPathname'; export const LOGIN_PATHNAME = 'loginPathname';
@ -21,7 +22,7 @@ export function fetchLoginRedirect() {
const loginSearch = localStorage.getItem(LOGIN_SEARCH); const loginSearch = localStorage.getItem(LOGIN_SEARCH);
clearLoginRedirect(); clearLoginRedirect();
return { return {
pathname: loginPathname || "/wifi/", pathname: loginPathname || `/${PROJECT_PATH}/`,
search: (loginPathname && loginSearch) || undefined search: (loginPathname && loginSearch) || undefined
}; };
} }

View File

@ -30,7 +30,8 @@ import CardContent from '@material-ui/core/CardContent';
import CardActions from '@material-ui/core/CardActions'; import CardActions from '@material-ui/core/CardActions';
import Avatar from '@material-ui/core/Avatar'; import Avatar from '@material-ui/core/Avatar';
import { APP_NAME } from '../constants/App'; import ProjectMenu from '../project/ProjectMenu';
import { PROJECT_NAME } from '../constants/Env';
import { withAuthenticationContext } from '../authentication/Context.js'; import { withAuthenticationContext } from '../authentication/Context.js';
const drawerWidth = 290; const drawerWidth = 290;
@ -65,8 +66,7 @@ const styles = theme => ({
width: drawerWidth, width: drawerWidth,
}, },
content: { content: {
flexGrow: 1, flexGrow: 1
padding: theme.spacing(),
}, },
authMenu: { authMenu: {
zIndex: theme.zIndex.tooltip, zIndex: theme.zIndex.tooltip,
@ -112,11 +112,13 @@ class MenuAppBar extends React.Component {
<div> <div>
<Toolbar> <Toolbar>
<Typography variant="h6" color="primary"> <Typography variant="h6" color="primary">
{APP_NAME} {PROJECT_NAME}
</Typography> </Typography>
<Divider absolute /> <Divider absolute />
</Toolbar> </Toolbar>
<Divider /> <Divider />
<ProjectMenu />
<Divider />
<List> <List>
<ListItem to='/wifi/' selected={path.startsWith('/wifi/')} button component={Link}> <ListItem to='/wifi/' selected={path.startsWith('/wifi/')} button component={Link}>
<ListItemIcon> <ListItemIcon>

View File

@ -8,15 +8,15 @@ import Typography from '@material-ui/core/Typography';
const styles = theme => ({ const styles = theme => ({
content: { content: {
padding: theme.spacing(2), padding: theme.spacing(2),
margin: theme.spacing(2), margin: theme.spacing(3),
} }
}); });
function SectionContent(props) { function SectionContent(props) {
const { children, classes, title } = props; const { children, classes, title, titleGutter } = props;
return ( return (
<Paper className={classes.content}> <Paper className={classes.content}>
<Typography variant="h6"> <Typography variant="h6" gutterBottom={titleGutter}>
{title} {title}
</Typography> </Typography>
{children} {children}
@ -30,7 +30,8 @@ SectionContent.propTypes = {
PropTypes.arrayOf(PropTypes.node), PropTypes.arrayOf(PropTypes.node),
PropTypes.node PropTypes.node
]).isRequired, ]).isRequired,
title: PropTypes.string.isRequired title: PropTypes.string.isRequired,
titleGutter: PropTypes.bool
}; };
export default withStyles(styles)(SectionContent); export default withStyles(styles)(SectionContent);

View File

@ -1 +0,0 @@
export const APP_NAME = process.env.REACT_APP_NAME;

View File

@ -0,0 +1,2 @@
export const PROJECT_NAME = process.env.REACT_APP_PROJECT_NAME;
export const PROJECT_PATH = process.env.REACT_APP_PROJECT_PATH;

View File

@ -96,9 +96,7 @@ class APStatus extends Component {
return ( return (
<div> <div>
<List> <List>
<Fragment> {this.createListItems(data, classes)}
{this.createListItems(data, classes)}
</Fragment>
</List> </List>
<Button variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}> <Button variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh Refresh

View File

@ -14,7 +14,7 @@ class ManageUsers extends Component {
render() { render() {
const { data, fetched, errorMessage } = this.props; const { data, fetched, errorMessage } = this.props;
return ( return (
<SectionContent title="Manage Users"> <SectionContent title="Manage Users" titleGutter>
<ManageUsersForm <ManageUsersForm
userData={data} userData={data}
userDataFetched={fetched} userDataFetched={fetched}

View File

@ -4,7 +4,7 @@ import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import Paper from '@material-ui/core/Paper'; import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import Fab from '@material-ui/core/Fab'; import Fab from '@material-ui/core/Fab';
import { APP_NAME } from '../constants/App'; import { PROJECT_NAME } from '../constants/Env';
import ForwardIcon from '@material-ui/icons/Forward'; import ForwardIcon from '@material-ui/icons/Forward';
import { withNotifier } from '../components/SnackbarNotification'; import { withNotifier } from '../components/SnackbarNotification';
import { SIGN_IN_ENDPOINT } from '../constants/Endpoints'; import { SIGN_IN_ENDPOINT } from '../constants/Endpoints';
@ -95,7 +95,7 @@ class SignInPage extends Component {
return ( return (
<div className={classes.loginPage}> <div className={classes.loginPage}>
<Paper className={classes.loginPanel}> <Paper className={classes.loginPanel}>
<Typography variant="h4">{APP_NAME}</Typography> <Typography variant="h4">{PROJECT_NAME}</Typography>
<ValidatorForm onSubmit={this.onSubmit}> <ValidatorForm onSubmit={this.onSubmit}>
<TextValidator <TextValidator
disabled={processing} disabled={processing}

View File

@ -0,0 +1,22 @@
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import SectionContent from '../components/SectionContent';
const styles = theme => ({
});
class DemoController extends Component {
render() {
return (
<SectionContent title="Controller" titleGutter>
TODO - This will contain a form which controls the speed of the built in LED.
</SectionContent>
)
}
}
export default withStyles(styles)(DemoController);

View File

@ -0,0 +1,99 @@
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableHead from '@material-ui/core/TableHead';
import TableCell from '@material-ui/core/TableCell';
import TableBody from '@material-ui/core/TableBody';
import TableRow from '@material-ui/core/TableRow';
import Typography from '@material-ui/core/Typography';
import SectionContent from '../components/SectionContent';
const styles = theme => ({
fileTable: {
marginBottom: theme.spacing(2)
}
});
class DemoInformation extends Component {
render() {
const { classes } = this.props;
return (
<SectionContent title="Demo Project - Blink Speed Controller" titleGutter>
<Typography variant="body1" paragraph>
This simple demo project allows you to control the blink speed of the built-in LED.
It demonstrates how the esp8266-react framework may be extended for your own IoT project.
</Typography>
<Typography variant="body1" paragraph>
It is recommended that you keep your project interface code under the 'project' directory.
This serves to isolate your project code from the from the rest of the user interface which should
simplify merges should you wish to update your project with future framework changes.
</Typography>
<Typography variant="body1" paragraph>
The demo project interface code is structured as follows:
</Typography>
<Table className={classes.fileTable}>
<TableHead>
<TableRow>
<TableCell>
File
</TableCell>
<TableCell>
Description
</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>
project/ProjectMenu.js
</TableCell>
<TableCell>
You can add your project's screens to the side bar here.
</TableCell>
</TableRow>
<TableRow>
<TableCell>
project/ProjectRouting.js
</TableCell>
<TableCell>
The routing which controls the screens of your project.
</TableCell>
</TableRow>
<TableRow>
<TableCell>
project/DemoProject.js
</TableCell>
<TableCell>
This screen, with tabs and tab routing.
</TableCell>
</TableRow>
<TableRow>
<TableCell>
project/DemoInformation.js
</TableCell>
<TableCell>
The demo information tab.
</TableCell>
</TableRow>
<TableRow>
<TableCell>
project/DemoController.js
</TableCell>
<TableCell>
The demo controller tab, to control the built-in LED.
</TableCell>
</TableRow>
</TableBody>
</Table>
<Typography variant="body1" paragraph>
See the project <a href="https://github.com/rjwats/esp8266-react/">README</a> for a full description of the demo project.
</Typography>
</SectionContent>
)
}
}
export default withStyles(styles)(DemoInformation);

View File

@ -0,0 +1,37 @@
import React, { Component } from 'react';
import { Redirect, Switch } from 'react-router-dom'
import { PROJECT_PATH } from '../constants/Env';
import MenuAppBar from '../components/MenuAppBar';
import AuthenticatedRoute from '../authentication/AuthenticatedRoute';
import DemoInformation from './DemoInformation';
import DemoController from './DemoController';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
class DemoProject extends Component {
handleTabChange = (event, path) => {
this.props.history.push(path);
};
render() {
return (
<MenuAppBar sectionTitle="Demo Project">
<Tabs value={this.props.match.url} onChange={this.handleTabChange} indicatorColor="primary" textColor="primary" variant="fullWidth">
<Tab value={`/${PROJECT_PATH}/demo/information`} label="Information" />
<Tab value={`/${PROJECT_PATH}/demo/controller`} label="Controller" />
</Tabs>
<Switch>
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/information`} component={DemoInformation} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/controller`} component={DemoController} />
<Redirect to={`/${PROJECT_PATH}/demo/information`} />
</Switch>
</MenuAppBar>
)
}
}
export default DemoProject;

View File

@ -0,0 +1,31 @@
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import { PROJECT_PATH } from '../constants/Env';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import SettingsRemoteIcon from '@material-ui/icons/SettingsRemote';
import Divider from '@material-ui/core/Divider';
class ProjectMenu extends Component {
render() {
const path = this.props.match.url;
return (
<List>
<ListItem to={`/${PROJECT_PATH}/demo/`} selected={path.startsWith(`/${PROJECT_PATH}/demo/`)} button component={Link}>
<ListItemIcon>
<SettingsRemoteIcon />
</ListItemIcon>
<ListItemText primary="Demo Project" />
</ListItem>
</List>
)
}
}
export default withRouter(ProjectMenu);

View File

@ -0,0 +1,32 @@
import React, { Component } from 'react';
import { Redirect, Switch } from 'react-router';
import { PROJECT_PATH } from '../constants/Env';
import AuthenticatedRoute from '../authentication/AuthenticatedRoute';
import DemoProject from './DemoProject';
class ProjectRouting extends Component {
render() {
return (
<Switch>
{
/*
* Add your project page routing below.
*/
}
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/*`} component={DemoProject} />
{
/*
* The redirect below caters for the default project route and redirecting invalid paths.
* The "to" property must match one of the routes above for this to work correctly.
*/
}
<Redirect to={`/${PROJECT_PATH}/demo/`} />
</Switch>
)
}
}
export default ProjectRouting;

View File

@ -32,6 +32,7 @@ class NetworkTime extends Component {
</MenuAppBar> </MenuAppBar>
) )
} }
} }
export default withAuthenticationContext(NetworkTime) export default withAuthenticationContext(NetworkTime)