mirror of
https://git.netzspielplatz.de/docker-multiarch/openwrt-firmware-selector.git
synced 2025-11-08 20:39:25 +00:00
Add ESLint to maintain code style. Add pre-commit hook to lint prior.
ESLint is used with the standard react plugin. It detects all kinds of issues ranging from misspells, indentation, variable-naming, etc. A pre-commit hook is added to git. Prior commiting, ESlint will run to validate that everything is OK and the user will have the option to fix it. Signed-off-by: Sudhanshu Gautam <me@sudhanshug.com>
This commit is contained in:
parent
d30cf925b1
commit
9475f4092a
13 changed files with 1116 additions and 1036 deletions
1
.eslintignore
Normal file
1
.eslintignore
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
src/serviceWorker.js
|
||||||
34
.eslintrc.yml
Normal file
34
.eslintrc.yml
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
env:
|
||||||
|
browser: true
|
||||||
|
es6: true
|
||||||
|
jest: true
|
||||||
|
extends:
|
||||||
|
- 'eslint:recommended'
|
||||||
|
- 'plugin:react/recommended'
|
||||||
|
globals:
|
||||||
|
Atomics: readonly
|
||||||
|
SharedArrayBuffer: readonly
|
||||||
|
parser: 'babel-eslint'
|
||||||
|
parserOptions:
|
||||||
|
ecmaFeatures:
|
||||||
|
jsx: true
|
||||||
|
ecmaVersion: 2018
|
||||||
|
sourceType: module
|
||||||
|
plugins:
|
||||||
|
- react
|
||||||
|
settings:
|
||||||
|
react:
|
||||||
|
version: 'detect'
|
||||||
|
rules:
|
||||||
|
indent:
|
||||||
|
- error
|
||||||
|
- 2
|
||||||
|
linebreak-style:
|
||||||
|
- error
|
||||||
|
- unix
|
||||||
|
quotes:
|
||||||
|
- error
|
||||||
|
- single
|
||||||
|
semi:
|
||||||
|
- error
|
||||||
|
- always
|
||||||
10
package.json
10
package.json
|
|
@ -24,7 +24,8 @@
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"predeploy": "yarn run build",
|
"predeploy": "yarn run build",
|
||||||
"deploy": "gh-pages -d build"
|
"deploy": "gh-pages -d build",
|
||||||
|
"lint": "eslint src/ --ext .js --fix"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": "react-app"
|
"extends": "react-app"
|
||||||
|
|
@ -40,5 +41,12 @@
|
||||||
"last 1 firefox version",
|
"last 1 firefox version",
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-eslint": "^10.0.2",
|
||||||
|
"eslint": "^6.1.0",
|
||||||
|
"eslint-plugin-react": "^7.14.2",
|
||||||
|
"prop-types": "latest",
|
||||||
|
"typescript": "^3.5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
src/App.js
30
src/App.js
|
|
@ -22,21 +22,21 @@ const theme = createMuiTheme({
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<Suspense fallback={
|
<Suspense fallback={
|
||||||
<LinearProgress/>
|
<LinearProgress/>
|
||||||
}>
|
}>
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<Header/>
|
<Header/>
|
||||||
<Router>
|
<Router>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="" component={Home}/>
|
<Route path="" component={Home}/>
|
||||||
<Route default component={NotFound}/>
|
<Route default component={NotFound}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Router>
|
</Router>
|
||||||
</div>
|
</div>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
50
src/components/alert-dialog.js
Normal file
50
src/components/alert-dialog.js
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@material-ui/core';
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
function AlertDialog({open, cancelHandler, acceptHandler, text, title, cancelComponent, acceptComponent}) {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={cancelHandler}
|
||||||
|
aria-labelledby="alert-dialog-title"
|
||||||
|
aria-describedby="alert-dialog-description"
|
||||||
|
>
|
||||||
|
<DialogTitle
|
||||||
|
id="alert-dialog-title">{title}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText id="alert-dialog-description">
|
||||||
|
{text}
|
||||||
|
</DialogContentText>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={acceptHandler} color="primary">
|
||||||
|
{acceptComponent}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={cancelHandler} color="secondary"
|
||||||
|
variant="contained" autoFocus>
|
||||||
|
{cancelComponent}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.propTypes = {
|
||||||
|
open: PropTypes.boolean,
|
||||||
|
cancelHandler: PropTypes.func,
|
||||||
|
acceptHandler: PropTypes.func,
|
||||||
|
text: PropTypes.string,
|
||||||
|
title: PropTypes.string,
|
||||||
|
cancelComponent: PropTypes.elementType,
|
||||||
|
acceptComponent: PropTypes.elementType,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlertDialog;
|
||||||
54
src/components/device-search.js
Normal file
54
src/components/device-search.js
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import {InputAdornment, makeStyles, TextField} from '@material-ui/core';
|
||||||
|
import {fade} from '@material-ui/core/styles';
|
||||||
|
import SearchIcon from '@material-ui/icons/Search';
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const useStylesSearch = makeStyles(theme => ({
|
||||||
|
root: {
|
||||||
|
borderColor: '#e2e2e1',
|
||||||
|
overflow: 'hidden',
|
||||||
|
margin: 0,
|
||||||
|
borderRadius: 4,
|
||||||
|
transition: theme.transitions.create(['border-color', 'box-shadow']),
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: fade(theme.palette.primary.main, 0.25),
|
||||||
|
},
|
||||||
|
'&$focused': {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 2px`,
|
||||||
|
borderColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
focused: {},
|
||||||
|
}));
|
||||||
|
|
||||||
|
function SearchTextField(props) {
|
||||||
|
const classes = useStylesSearch();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
variant="outlined"
|
||||||
|
label={
|
||||||
|
<div className="search-label">
|
||||||
|
{props.labeltext}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
InputProps={
|
||||||
|
{
|
||||||
|
classes,
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SearchIcon className={classes.label}/>
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} {...props} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchTextField.propTypes = {
|
||||||
|
labeltext: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SearchTextField;
|
||||||
68
src/components/error-snackbar.js
Normal file
68
src/components/error-snackbar.js
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import {
|
||||||
|
IconButton,
|
||||||
|
makeStyles,
|
||||||
|
Snackbar,
|
||||||
|
SnackbarContent,
|
||||||
|
} from '@material-ui/core';
|
||||||
|
import ErrorIcon from '@material-ui/icons/Error';
|
||||||
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const SnackBarStyles = makeStyles(theme => ({
|
||||||
|
error: {
|
||||||
|
backgroundColor: theme.palette.error.dark,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
marginRight: '20px',
|
||||||
|
fontSize: 20,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
function ErrorSnackBar({open, closeHandle, errorMessage}) {
|
||||||
|
const classes = SnackBarStyles();
|
||||||
|
return (
|
||||||
|
<Snackbar
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'left',
|
||||||
|
}}
|
||||||
|
open={open}
|
||||||
|
autoHideDuration={6000}
|
||||||
|
onClose={closeHandle}
|
||||||
|
ContentProps={{
|
||||||
|
'aria-describedby': 'message-id',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SnackbarContent
|
||||||
|
className={classes.error}
|
||||||
|
aria-describedby="client-snackbar"
|
||||||
|
message={
|
||||||
|
<span id="client-snackbar" className={classes.message}>
|
||||||
|
<ErrorIcon className={classes.icon}/>
|
||||||
|
{errorMessage ||
|
||||||
|
'An unexpected error occurred. Please try again'}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
action={[
|
||||||
|
<IconButton key="close" aria-label="Close" color="inherit"
|
||||||
|
onClick={closeHandle}>
|
||||||
|
<CloseIcon/>
|
||||||
|
</IconButton>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Snackbar>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorSnackBar.propTypes = {
|
||||||
|
open: PropTypes.boolean,
|
||||||
|
closeHandle: PropTypes.func,
|
||||||
|
errorMessage: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ErrorSnackBar;
|
||||||
|
|
@ -39,46 +39,46 @@ export default function Header() {
|
||||||
const id = open ? 'simple-popper' : undefined;
|
const id = open ? 'simple-popper' : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar position="static">
|
<AppBar position="static">
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Typography edge="start" variant="h6">{t(
|
<Typography edge="start" variant="h6">{t(
|
||||||
'OpenWrt Firmware Selector Wizard')}</Typography>
|
'OpenWrt Firmware Selector Wizard')}</Typography>
|
||||||
<div style={{flexGrow: 1}} />
|
<div style={{flexGrow: 1}} />
|
||||||
<Button aria-describedby={id} color="secondary" variant="contained"
|
<Button aria-describedby={id} color="secondary" variant="contained"
|
||||||
onClick={openChangeLanguagePopper} href="#">
|
onClick={openChangeLanguagePopper} href="#">
|
||||||
{t('Change Language')}
|
{t('Change Language')}
|
||||||
<LanguageIcon/>
|
<LanguageIcon/>
|
||||||
</Button>
|
</Button>
|
||||||
<Popper
|
<Popper
|
||||||
id={id}
|
id={id}
|
||||||
open={open}
|
open={open}
|
||||||
anchorEl={anchorEl}
|
anchorEl={anchorEl}
|
||||||
transition
|
transition
|
||||||
disablePortal={true}
|
disablePortal={true}
|
||||||
>
|
>
|
||||||
{({TransitionProps}) => (
|
{({TransitionProps}) => (
|
||||||
<Fade {...TransitionProps} timeout={350}>
|
<Fade {...TransitionProps} timeout={350}>
|
||||||
<Paper className="language-selector-popper">
|
<Paper className="language-selector-popper">
|
||||||
<FormControl component="fieldset">
|
<FormControl component="fieldset">
|
||||||
<FormLabel component="legend">Change Language</FormLabel>
|
<FormLabel component="legend">Change Language</FormLabel>
|
||||||
<br/>
|
<br/>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
aria-label="Language"
|
aria-label="Language"
|
||||||
name="language"
|
name="language"
|
||||||
value={value}
|
value={value}
|
||||||
onChange={changeLanguage}
|
onChange={changeLanguage}
|
||||||
>
|
>
|
||||||
<FormControlLabel value="en" control={<Radio/>}
|
<FormControlLabel value="en" control={<Radio/>}
|
||||||
label={t('English')}/>
|
label={t('English')}/>
|
||||||
<FormControlLabel value="de" control={<Radio/>}
|
<FormControlLabel value="de" control={<Radio/>}
|
||||||
label={t('German')}/>
|
label={t('German')}/>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Fade>
|
</Fade>
|
||||||
)}
|
)}
|
||||||
</Popper>
|
</Popper>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,9 @@ import {
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
ClickAwayListener,
|
ClickAwayListener,
|
||||||
Container,
|
Container,
|
||||||
Dialog,
|
|
||||||
DialogActions,
|
|
||||||
DialogContent,
|
|
||||||
DialogContentText,
|
|
||||||
DialogTitle,
|
|
||||||
FormControl,
|
FormControl,
|
||||||
Grid,
|
Grid,
|
||||||
IconButton,
|
|
||||||
Input,
|
Input,
|
||||||
InputAdornment,
|
|
||||||
InputLabel,
|
InputLabel,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
|
|
@ -24,158 +17,39 @@ import {
|
||||||
OutlinedInput,
|
OutlinedInput,
|
||||||
Paper,
|
Paper,
|
||||||
Select,
|
Select,
|
||||||
Snackbar,
|
|
||||||
SnackbarContent,
|
|
||||||
Tab,
|
Tab,
|
||||||
Tabs,
|
Tabs,
|
||||||
TextField,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import {fade, makeStyles} from '@material-ui/core/styles';
|
|
||||||
|
|
||||||
import SearchIcon from '@material-ui/icons/Search';
|
|
||||||
import CloudDownloadIcon from '@material-ui/icons/CloudDownload';
|
import CloudDownloadIcon from '@material-ui/icons/CloudDownload';
|
||||||
import WarningIcon from '@material-ui/icons/Warning';
|
import WarningIcon from '@material-ui/icons/Warning';
|
||||||
import BuildIcon from '@material-ui/icons/Build';
|
import BuildIcon from '@material-ui/icons/Build';
|
||||||
import CloseIcon from '@material-ui/icons/Close';
|
|
||||||
import ErrorIcon from '@material-ui/icons/Error';
|
|
||||||
import './home.scss';
|
import './home.scss';
|
||||||
import {withTranslation} from 'react-i18next';
|
import {withTranslation} from 'react-i18next';
|
||||||
import FuzzySet from 'fuzzyset.js';
|
import FuzzySet from 'fuzzyset.js';
|
||||||
|
|
||||||
import DataService from '../../services/data';
|
import DataService from '../../services/data';
|
||||||
|
|
||||||
|
import AlertDialog from '../../components/alert-dialog';
|
||||||
|
import ErrorSnackBar from '../../components/error-snackbar';
|
||||||
|
import SearchTextField from '../../components/device-search';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const buildStatusCheckInterval = 5000;
|
const buildStatusCheckInterval = 5000;
|
||||||
|
|
||||||
const useStylesSearch = makeStyles(theme => ({
|
|
||||||
root: {
|
|
||||||
borderColor: '#e2e2e1',
|
|
||||||
overflow: 'hidden',
|
|
||||||
margin: 0,
|
|
||||||
borderRadius: 4,
|
|
||||||
transition: theme.transitions.create(['border-color', 'box-shadow']),
|
|
||||||
'&:hover': {
|
|
||||||
borderColor: fade(theme.palette.primary.main, 0.25),
|
|
||||||
},
|
|
||||||
'&$focused': {
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 2px`,
|
|
||||||
borderColor: theme.palette.primary.main,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
focused: {},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const SnackBarStyles = makeStyles(theme => ({
|
|
||||||
error: {
|
|
||||||
backgroundColor: theme.palette.error.dark,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
marginRight: '20px',
|
|
||||||
fontSize: 20,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
function ErrorSnackBar({open, closeHandle, errorMessage}) {
|
|
||||||
const classes = SnackBarStyles();
|
|
||||||
return (
|
|
||||||
<Snackbar
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'bottom',
|
|
||||||
horizontal: 'left',
|
|
||||||
}}
|
|
||||||
open={open}
|
|
||||||
autoHideDuration={6000}
|
|
||||||
onClose={closeHandle}
|
|
||||||
ContentProps={{
|
|
||||||
'aria-describedby': 'message-id',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SnackbarContent
|
|
||||||
className={classes.error}
|
|
||||||
aria-describedby="client-snackbar"
|
|
||||||
message={
|
|
||||||
<span id="client-snackbar" className={classes.message}>
|
|
||||||
<ErrorIcon className={classes.icon}/>
|
|
||||||
{errorMessage ||
|
|
||||||
'An unexpected error occurred. Please try again'}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
action={[
|
|
||||||
<IconButton key="close" aria-label="Close" color="inherit"
|
|
||||||
onClick={closeHandle}>
|
|
||||||
<CloseIcon/>
|
|
||||||
</IconButton>,
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</Snackbar>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SearchTextField(props) {
|
|
||||||
const classes = useStylesSearch();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TextField
|
|
||||||
variant="outlined"
|
|
||||||
label={
|
|
||||||
<div className="search-label">
|
|
||||||
{props.labeltext}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
InputProps={
|
|
||||||
{
|
|
||||||
classes,
|
|
||||||
endAdornment: (
|
|
||||||
<InputAdornment position="start">
|
|
||||||
<SearchIcon className={classes.label}/>
|
|
||||||
</InputAdornment>
|
|
||||||
),
|
|
||||||
}
|
|
||||||
} {...props} />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function TabContainer({children, dir}) {
|
function TabContainer({children, dir}) {
|
||||||
return (
|
return (
|
||||||
<Typography component="div" dir={dir} style={{padding: '20px 0 0'}}>
|
<Typography component="div" dir={dir} style={{padding: '20px 0 0'}}>
|
||||||
{children}
|
{children}
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AlertDialog({open, cancelHandler, acceptHandler, text, title, cancelComponent, acceptComponent}) {
|
TabContainer.propTypes = {
|
||||||
return (
|
children: PropTypes.elementType,
|
||||||
<Dialog
|
dir: PropTypes.any,
|
||||||
open={open}
|
};
|
||||||
onClose={cancelHandler}
|
|
||||||
aria-labelledby="alert-dialog-title"
|
|
||||||
aria-describedby="alert-dialog-description"
|
|
||||||
>
|
|
||||||
<DialogTitle
|
|
||||||
id="alert-dialog-title">{title}</DialogTitle>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogContentText id="alert-dialog-description">
|
|
||||||
{text}
|
|
||||||
</DialogContentText>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button onClick={acceptHandler} color="primary">
|
|
||||||
{acceptComponent}
|
|
||||||
</Button>
|
|
||||||
<Button onClick={cancelHandler} color="secondary"
|
|
||||||
variant="contained" autoFocus>
|
|
||||||
{cancelComponent}
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Home extends React.Component {
|
class Home extends React.Component {
|
||||||
|
|
||||||
|
|
@ -323,7 +197,7 @@ class Home extends React.Component {
|
||||||
this.basicInterface = val;
|
this.basicInterface = val;
|
||||||
};
|
};
|
||||||
|
|
||||||
downloadingImageIndicatorShow = (i) => {
|
downloadingImageIndicatorShow = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
downloading: true,
|
downloading: true,
|
||||||
});
|
});
|
||||||
|
|
@ -367,7 +241,7 @@ class Home extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
closeConfirmBuildDialog = (v) => {
|
closeConfirmBuildDialog = () => {
|
||||||
this.confirmingBuild = false;
|
this.confirmingBuild = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -378,36 +252,36 @@ class Home extends React.Component {
|
||||||
displayBuiltImageData = async (buildStatusResponse) => {
|
displayBuiltImageData = async (buildStatusResponse) => {
|
||||||
console.log(buildStatusResponse);
|
console.log(buildStatusResponse);
|
||||||
await this.dataService.getFiles(buildStatusResponse.data.files)
|
await this.dataService.getFiles(buildStatusResponse.data.files)
|
||||||
.then((fileListResponse) => {
|
.then((fileListResponse) => {
|
||||||
let builtImages = [];
|
let builtImages = [];
|
||||||
fileListResponse.forEach((file) => {
|
fileListResponse.forEach((file) => {
|
||||||
const suffix = file.name.substring(file.name.length - 4);
|
const suffix = file.name.substring(file.name.length - 4);
|
||||||
if (suffix === '.bin') {
|
if (suffix === '.bin') {
|
||||||
const type = file.name.split('-').reverse()[0].split('.')[0];
|
const type = file.name.split('-').reverse()[0].split('.')[0];
|
||||||
builtImages.push({
|
builtImages.push({
|
||||||
url: 'https://chef.libremesh.org' +
|
url: 'https://chef.libremesh.org' +
|
||||||
buildStatusResponse.data.files + file.name,
|
buildStatusResponse.data.files + file.name,
|
||||||
type,
|
type,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
builtImages,
|
|
||||||
configChanged: false,
|
|
||||||
isBuilding: false,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
this.setState({
|
||||||
|
builtImages,
|
||||||
|
configChanged: false,
|
||||||
|
isBuilding: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
clearTimeout(this.checkBuildStatus);
|
clearTimeout(this.checkBuildStatus);
|
||||||
};
|
};
|
||||||
|
|
||||||
buildImageCheck = async (request_hash) => {
|
buildImageCheck = async (request_hash) => {
|
||||||
const buildStatusResponse = await this.dataService.buildStatusCheck(
|
const buildStatusResponse = await this.dataService.buildStatusCheck(
|
||||||
request_hash);
|
request_hash);
|
||||||
if (buildStatusResponse.status === 202) {
|
if (buildStatusResponse.status === 202) {
|
||||||
this.checkBuildStatus = setTimeout(
|
this.checkBuildStatus = setTimeout(
|
||||||
() => {
|
async () => {
|
||||||
this.buildImageCheck(request_hash);
|
await this.buildImageCheck(request_hash);
|
||||||
}, buildStatusCheckInterval,
|
}, buildStatusCheckInterval,
|
||||||
);
|
);
|
||||||
} else if (buildStatusResponse.status === 200) {
|
} else if (buildStatusResponse.status === 200) {
|
||||||
await this.displayBuiltImageData(buildStatusResponse);
|
await this.displayBuiltImageData(buildStatusResponse);
|
||||||
|
|
@ -423,7 +297,7 @@ class Home extends React.Component {
|
||||||
this.closeConfirmBuildDialog();
|
this.closeConfirmBuildDialog();
|
||||||
const board = this.state.device.id;
|
const board = this.state.device.id;
|
||||||
const packages = this.state.packages;
|
const packages = this.state.packages;
|
||||||
const target = this.state.device.target + '/' + this.state.device.subtarget;
|
const target = this.state.device['target'] + '/' + this.state.device['subtarget'];
|
||||||
const version = this.state.release;
|
const version = this.state.release;
|
||||||
this.setState({
|
this.setState({
|
||||||
isBuilding: true,
|
isBuilding: true,
|
||||||
|
|
@ -433,9 +307,9 @@ class Home extends React.Component {
|
||||||
if (res.status === 202 && res.data['request_hash'] !== undefined) {
|
if (res.status === 202 && res.data['request_hash'] !== undefined) {
|
||||||
const request_hash = res.data['request_hash'];
|
const request_hash = res.data['request_hash'];
|
||||||
this.checkBuildStatus = setTimeout(
|
this.checkBuildStatus = setTimeout(
|
||||||
async () => {
|
async () => {
|
||||||
await this.buildImageCheck(request_hash);
|
await this.buildImageCheck(request_hash);
|
||||||
}, buildStatusCheckInterval,
|
}, buildStatusCheckInterval,
|
||||||
);
|
);
|
||||||
} else if (res.status === 200) {
|
} else if (res.status === 200) {
|
||||||
await this.displayBuiltImageData(res);
|
await this.displayBuiltImageData(res);
|
||||||
|
|
@ -456,26 +330,26 @@ class Home extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const warning432 = this.state.showDeviceData &&
|
const warning432 = this.state.showDeviceData &&
|
||||||
parseInt(
|
parseInt(
|
||||||
(this.state.device['image_size'] || '').slice(0, -1)) <= 4000 && (
|
(this.state.device['image_size'] || '').slice(0, -1)) <= 4000 && (
|
||||||
<Paper className="warning-432" elevation={0}>
|
<Paper className="warning-432" elevation={0}>
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
direction="row"
|
direction="row"
|
||||||
justify="center"
|
justify="center"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
>
|
>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<WarningIcon className="icon"/>
|
<WarningIcon className="icon"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs>
|
<Grid item xs>
|
||||||
{this.props.t(
|
{this.props.t(
|
||||||
'Devices with ≤4MB flash and/or ≤32MB ram will work but they will be very limited (usually they can\'t install or run additional packages) because they have low RAM and flash space. Consider this when choosing a device to buy, or when deciding to flash OpenWrt on your device because it is listed as supported.')}
|
'Devices with ≤4MB flash and/or ≤32MB ram will work but they will be very limited (usually they can\'t install or run additional packages) because they have low RAM and flash space. Consider this when choosing a device to buy, or when deciding to flash OpenWrt on your device because it is listed as supported.')}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
const notLoaded = (
|
const notLoaded = (
|
||||||
<CircularProgress/>
|
<CircularProgress/>
|
||||||
);
|
);
|
||||||
const onLoad = (
|
const onLoad = (
|
||||||
<>
|
<>
|
||||||
|
|
@ -484,7 +358,7 @@ class Home extends React.Component {
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{this.props.t(
|
{this.props.t(
|
||||||
'Please use the input below to download firmware for your device!')}
|
'Please use the input below to download firmware for your device!')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<br/>
|
<br/>
|
||||||
<ClickAwayListener onClickAway={this.hideSearchResults}>
|
<ClickAwayListener onClickAway={this.hideSearchResults}>
|
||||||
|
|
@ -494,65 +368,65 @@ class Home extends React.Component {
|
||||||
{this.props.t('Version')}
|
{this.props.t('Version')}
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
value={this.state.release}
|
value={this.state.release}
|
||||||
onChange={this.setRelease}
|
onChange={this.setRelease}
|
||||||
input={<OutlinedInput name="version"
|
input={<OutlinedInput name="version"
|
||||||
id="version-select" labelWidth={60}/>}
|
id="version-select" labelWidth={60}/>}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
Object.keys(this.state.distributions['versions'])
|
Object.keys(this.state.distributions['versions'])
|
||||||
.map((version) => (
|
.map((version) => (
|
||||||
<MenuItem value={version} key={version}>
|
<MenuItem value={version} key={version}>
|
||||||
<em>{version}</em>
|
<em>{version}</em>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl className="search-field">
|
<FormControl className="search-field">
|
||||||
<SearchTextField
|
<SearchTextField
|
||||||
id="outlined-adornment-search-devices"
|
id="outlined-adornment-search-devices"
|
||||||
labeltext={this.props.t('Search your device')}
|
labeltext={this.props.t('Search your device')}
|
||||||
value={this.state.query}
|
value={this.state.query}
|
||||||
onChange={this.search}
|
onChange={this.search}
|
||||||
onClick={this.search}
|
onClick={this.search}
|
||||||
/>
|
/>
|
||||||
{
|
{
|
||||||
this.state.showSearch && this.state.searchResults.length !==
|
this.state.showSearch && this.state.searchResults.length !==
|
||||||
0 && (
|
0 && (
|
||||||
<Paper elevation={4} className="search-results">
|
<Paper elevation={4} className="search-results">
|
||||||
<List>
|
<List>
|
||||||
{
|
{
|
||||||
this.state.searchResults.map((res, index) => {
|
this.state.searchResults.map((res) => {
|
||||||
return (
|
return (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={res}
|
key={res}
|
||||||
button
|
button
|
||||||
onClick={() => this.selectDevice(res)}
|
onClick={() => this.selectDevice(res)}
|
||||||
>
|
>
|
||||||
<ListItemText primary={
|
<ListItemText primary={
|
||||||
<div>
|
<div>
|
||||||
{res}
|
{res}
|
||||||
</div>
|
</div>
|
||||||
}/>
|
}/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</List>
|
</List>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
(this.state.searchResults.length === 0 &&
|
(this.state.searchResults.length === 0 &&
|
||||||
this.state.showSearch) && (
|
this.state.showSearch) && (
|
||||||
<Paper elevation={4} className="search-results">
|
<Paper elevation={4} className="search-results">
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={this.props.t('No results')}/>
|
primary={this.props.t('No results')}/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Paper>
|
</Paper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
@ -574,128 +448,128 @@ class Home extends React.Component {
|
||||||
<Grid container className="device-info">
|
<Grid container className="device-info">
|
||||||
<Grid item xs>
|
<Grid item xs>
|
||||||
<b>{this.props.t(
|
<b>{this.props.t(
|
||||||
'Name')}: </b> {this.state.device['title']}({this.state.device['target']}/{this.state.device['subtarget']})
|
'Name')}: </b> {this.state.device['title']}({this.state.device['target']}/{this.state.device['subtarget']})
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs>
|
<Grid item xs>
|
||||||
<b>{this.props.t(
|
<b>{this.props.t(
|
||||||
'Release Version')}: </b> {this.state.release_version_number}
|
'Release Version')}: </b> {this.state.release_version_number}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<AppBar className="interface-switch-bar" position="relative"
|
<AppBar className="interface-switch-bar" position="relative"
|
||||||
elevation={0}>
|
elevation={0}>
|
||||||
<Tabs value={this.basicInterface}
|
<Tabs value={this.basicInterface}
|
||||||
onChange={this.changeInterface}>
|
onChange={this.changeInterface}>
|
||||||
<Tab className="interface-switch"
|
<Tab className="interface-switch"
|
||||||
label={this.props.t('Basic')}/>
|
label={this.props.t('Basic')}/>
|
||||||
<Tab className="interface-switch"
|
<Tab className="interface-switch"
|
||||||
label={this.props.t('Advanced')}/>
|
label={this.props.t('Advanced')}/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
{
|
{
|
||||||
this.basicInterface === 0 ? (
|
this.basicInterface === 0 ? (
|
||||||
<TabContainer>
|
<TabContainer>
|
||||||
{
|
{
|
||||||
this.state.device.images.map((image, i) => {
|
this.state.device.images.map((image, i) => {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
key={i}
|
key={i}
|
||||||
className="download-button"
|
className="download-button"
|
||||||
href={'http://downloads.openwrt.org/snapshots/targets/' +
|
href={'http://downloads.openwrt.org/snapshots/targets/' +
|
||||||
this.state.device.target + '/' +
|
this.state.device.target + '/' +
|
||||||
this.state.device.subtarget + '/' +
|
this.state.device.subtarget + '/' +
|
||||||
image.name}
|
image.name}
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => this.downloadingImageIndicatorShow()}
|
onClick={() => this.downloadingImageIndicatorShow()}
|
||||||
>
|
>
|
||||||
<CloudDownloadIcon
|
<CloudDownloadIcon
|
||||||
className="download-icon"/>
|
className="download-icon"/>
|
||||||
{image.type}
|
{image.type}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
this.state.downloading && (
|
||||||
|
<CircularProgress size={20}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</TabContainer>
|
||||||
|
) : (
|
||||||
|
<TabContainer>
|
||||||
|
<Paper elevation={0} className="package-list-input">
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
this.state.packages.map((package_name, i) => {
|
||||||
|
return (
|
||||||
|
<Chip className="package"
|
||||||
|
key={package_name + i}
|
||||||
|
size="small"
|
||||||
|
onDelete={() => this.deletePackage(
|
||||||
|
i)}
|
||||||
|
label={package_name}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<Tooltip
|
||||||
|
title={<span>Use comma or new line separated array. <br/>Press enter to apply.</span>}>
|
||||||
|
<Input
|
||||||
|
multiline
|
||||||
|
value={this.state.packageName}
|
||||||
|
onKeyUp={this.addPackage}
|
||||||
|
onChange={this.changeAddPackageInput}
|
||||||
|
placeholder={this.props.t('Add package(s)')}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
{
|
{
|
||||||
this.state.downloading && (
|
this.state.configChanged && !this.state.isBuilding && (
|
||||||
<CircularProgress size={20}/>
|
<Button variant="outlined" color="primary"
|
||||||
|
onClick={this.openConfirmBuildDialog}>
|
||||||
|
<BuildIcon/>
|
||||||
|
|
||||||
|
{this.props.t('Build')}
|
||||||
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</TabContainer>
|
{
|
||||||
) : (
|
this.state.isBuilding && (
|
||||||
<TabContainer>
|
<CircularProgress size={20}/>
|
||||||
<Paper elevation={0} className="package-list-input">
|
)
|
||||||
<div>
|
}
|
||||||
{
|
{
|
||||||
this.state.packages.map((package_name, i) => {
|
this.state.builtImages.length > 0 && !this.state.configChanged && (
|
||||||
return (
|
|
||||||
<Chip className="package"
|
|
||||||
key={package_name + i}
|
|
||||||
size="small"
|
|
||||||
onDelete={() => this.deletePackage(
|
|
||||||
i)}
|
|
||||||
label={package_name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
<Tooltip
|
|
||||||
title={<span>Use comma or new line separated array. <br/>Press enter to apply.</span>}>
|
|
||||||
<Input
|
|
||||||
multiline
|
|
||||||
value={this.state.packageName}
|
|
||||||
onKeyUp={this.addPackage}
|
|
||||||
onChange={this.changeAddPackageInput}
|
|
||||||
placeholder={this.props.t('Add package(s)')}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
{
|
|
||||||
this.state.configChanged && !this.state.isBuilding && (
|
|
||||||
<Button variant="outlined" color="primary"
|
|
||||||
onClick={this.openConfirmBuildDialog}>
|
|
||||||
<BuildIcon/>
|
|
||||||
|
|
||||||
{this.props.t('Build')}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
this.state.isBuilding && (
|
|
||||||
<CircularProgress size={20}/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
this.state.builtImages.length > 0 && !this.state.configChanged && (
|
|
||||||
<>
|
<>
|
||||||
{
|
{
|
||||||
this.state.builtImages.map((image) => (
|
this.state.builtImages.map((image) => (
|
||||||
<Button
|
<Button
|
||||||
key={image.url}
|
key={image.url}
|
||||||
className="download-button"
|
className="download-button"
|
||||||
href={image.url}
|
href={image.url}
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => this.downloadingImageIndicatorShow()}
|
onClick={() => this.downloadingImageIndicatorShow()}
|
||||||
>
|
>
|
||||||
<CloudDownloadIcon
|
<CloudDownloadIcon
|
||||||
className="download-icon"/>
|
className="download-icon"/>
|
||||||
{image.type}
|
{image.type}
|
||||||
</Button>
|
</Button>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
this.state.downloading && (
|
this.state.downloading && (
|
||||||
<CircularProgress size={20}/>
|
<CircularProgress size={20}/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Paper>
|
</Paper>
|
||||||
</TabContainer>
|
</TabContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
|
|
@ -706,23 +580,23 @@ class Home extends React.Component {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ErrorSnackBar
|
<ErrorSnackBar
|
||||||
open={this.state.showUnexpectedErrorBar}
|
open={this.state.showUnexpectedErrorBar}
|
||||||
closeHandle={this.closeUnexpectedErrorBar}
|
closeHandle={this.closeUnexpectedErrorBar}
|
||||||
/>
|
/>
|
||||||
<AlertDialog
|
<AlertDialog
|
||||||
cancelHandler={this.closeConfirmBuildDialog}
|
cancelHandler={this.closeConfirmBuildDialog}
|
||||||
acceptHandler={this.buildImage}
|
acceptHandler={this.buildImage}
|
||||||
open={this.confirmingBuild}
|
open={this.confirmingBuild}
|
||||||
text={this.props.t(
|
text={this.props.t(
|
||||||
'Building image requires computation resources, so we would request you to check if this selection is what you want')}
|
'Building image requires computation resources, so we would request you to check if this selection is what you want')}
|
||||||
title={this.props.t(
|
title={this.props.t(
|
||||||
'Please confirm that you want to perform this action')}
|
'Please confirm that you want to perform this action')}
|
||||||
cancelComponent={this.props.t('Cancel')}
|
cancelComponent={this.props.t('Cancel')}
|
||||||
acceptComponent={
|
acceptComponent={
|
||||||
<>
|
<>
|
||||||
{this.props.t('Build')} <BuildIcon/>
|
{this.props.t('Build')} <BuildIcon/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Container className="home-container">
|
<Container className="home-container">
|
||||||
<Paper className="home-container-paper">
|
<Paper className="home-container-paper">
|
||||||
|
|
@ -734,4 +608,8 @@ class Home extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Home.propTypes = {
|
||||||
|
t: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
export default withTranslation()(Home);
|
export default withTranslation()(Home);
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,15 @@ const page404Styles = makeStyles(theme => ({
|
||||||
export default function NotFound() {
|
export default function NotFound() {
|
||||||
var classes = page404Styles();
|
var classes = page404Styles();
|
||||||
return (
|
return (
|
||||||
<Container style={{marginTop: '50px'}}>
|
<Container style={{marginTop: '50px'}}>
|
||||||
<Paper className={classes.root} elevation={3}>
|
<Paper className={classes.root} elevation={3}>
|
||||||
<Typography variant="h5" component="h3">
|
<Typography variant="h5" component="h3">
|
||||||
404 Page Not Found
|
404 Page Not Found
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography component="p">
|
<Typography component="p">
|
||||||
Please head to the home.
|
Please head to the home.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/i18n.js
18
src/i18n.js
|
|
@ -14,14 +14,14 @@ const resources = {
|
||||||
};
|
};
|
||||||
|
|
||||||
i18n.use(LanguageDetector)
|
i18n.use(LanguageDetector)
|
||||||
.use(initReactI18next)
|
.use(initReactI18next)
|
||||||
.init({
|
.init({
|
||||||
resources,
|
resources,
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
debug: true,
|
debug: true,
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false, // not needed for react as it escapes by default
|
escapeValue: false, // not needed for react as it escapes by default
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default i18n;
|
export default i18n;
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,18 @@ import axios from 'axios';
|
||||||
const base = 'https://cors-anywhere.herokuapp.com/https://mwarning.de/misc/json/bin';
|
const base = 'https://cors-anywhere.herokuapp.com/https://mwarning.de/misc/json/bin';
|
||||||
|
|
||||||
class DataService {
|
class DataService {
|
||||||
|
|
||||||
getDevicesData = axios.get(
|
getDevicesData = axios.get(
|
||||||
`${base}/overview.json`)
|
`${base}/overview.json`)
|
||||||
.then(res => res.data);
|
.then(res => res.data);
|
||||||
|
|
||||||
getDeviceData = (device_id) => axios.get(
|
getDeviceData = (device_id) => axios.get(
|
||||||
base + '/targets/' + device_id)
|
base + '/targets/' + device_id)
|
||||||
.then(res => res.data);
|
.then(res => res.data);
|
||||||
|
|
||||||
getDistributions = axios.get(
|
getDistributions = axios.get(
|
||||||
'https://chef.libremesh.org/api/distributions')
|
'https://chef.libremesh.org/api/distributions')
|
||||||
.then(res => res.data);
|
.then(res => res.data);
|
||||||
|
|
||||||
buildImage = (board, packages, target, version) => {
|
buildImage = (board, packages, target, version) => {
|
||||||
return axios.post('https://chef.libremesh.org/api/build-request', {
|
return axios.post('https://chef.libremesh.org/api/build-request', {
|
||||||
|
|
@ -34,7 +35,7 @@ class DataService {
|
||||||
response.isBuilt = res.status === 202 && res.data.files !== undefined;
|
response.isBuilt = res.status === 202 && res.data.files !== undefined;
|
||||||
response.status = res.status;
|
response.status = res.status;
|
||||||
if (response.isBuilt) {
|
if (response.isBuilt) {
|
||||||
response = {...response, data: res.data}
|
response = {...response, data: res.data};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return response;
|
return response;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue