Converted to bootstrap, ready for initial testing
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -64,4 +64,5 @@ typings/
|
|||||||
.vuepress/dist
|
.vuepress/dist
|
||||||
|
|
||||||
# Serverless directories
|
# Serverless directories
|
||||||
.serverless
|
.serverless
|
||||||
|
dist/*
|
||||||
|
|||||||
BIN
app/build/POCloud.png
Normal file
BIN
app/build/POCloud.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
File diff suppressed because one or more lines are too long
@@ -3,18 +3,11 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>POCloud Admin</title>
|
<title>POCloud Admin</title>
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||||
<!-- Compiled and minified CSS -->
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/css/materialize.min.css">
|
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
<script src="./build/bundle.js"></script>
|
||||||
<!-- Compiled and minified JavaScript -->
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>
|
|
||||||
<script src="./build/bundle.js"></script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -8,24 +8,19 @@ import {
|
|||||||
LOGIN_USER_SUCCESS,
|
LOGIN_USER_SUCCESS,
|
||||||
LOGIN_USER_FAIL,
|
LOGIN_USER_FAIL,
|
||||||
LOGOUT,
|
LOGOUT,
|
||||||
COMPANY_DATA_RECEIVED,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
import baseURL from '../Meshify';
|
import baseURL from '../Meshify';
|
||||||
|
|
||||||
export const emailChanged = (text) => {
|
export const emailChanged = text => ({
|
||||||
return {
|
type: EMAIL_CHANGED,
|
||||||
type: EMAIL_CHANGED,
|
payload: text,
|
||||||
payload: text,
|
});
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const passwordChanged = (text) => {
|
export const passwordChanged = text => ({
|
||||||
return {
|
type: PASSWORD_CHANGED,
|
||||||
type: PASSWORD_CHANGED,
|
payload: text,
|
||||||
payload: text,
|
});
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const loginUserSuccess = (dispatch, user, authToken) => {
|
const loginUserSuccess = (dispatch, user, authToken) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -49,15 +44,6 @@ export const loginUser = ({ email, password }) => {
|
|||||||
loginUserSuccess(dispatch, response.data, authToken);
|
loginUserSuccess(dispatch, response.data, authToken);
|
||||||
})
|
})
|
||||||
.catch(() => loginUserFail(dispatch));
|
.catch(() => loginUserFail(dispatch));
|
||||||
|
|
||||||
axios.get(`${baseURL}/companies`, { headers: { Authorization: authToken } })
|
|
||||||
.then((response) => {
|
|
||||||
dispatch({ type: COMPANY_DATA_RECEIVED, payload: response.data });
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log('AUTH', authToken);
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ export const getData = ({ authToken }) => {
|
|||||||
}
|
}
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
axios.get(`${baseURL}/companies`, { headers: { Authorization: authToken } })
|
axios.get(`${baseURL}/companies`, { headers: { Authorization: authToken } })
|
||||||
.then((response) => {
|
.then((companiesResponse) => {
|
||||||
dispatch({ type: COMPANY_DATA_RECEIVED, payload: response.data });
|
dispatch({ type: COMPANY_DATA_RECEIVED, payload: companiesResponse.data });
|
||||||
axios.get(`${baseURL}/devicetypes`, { headers: { Authorization: authToken } })
|
axios.get(`${baseURL}/devicetypes`, { headers: { Authorization: authToken } })
|
||||||
.then((response) => {
|
.then((devicetypesResponse) => {
|
||||||
dispatch({ type: DEVICETYPE_DATA_RECEIVED, payload: response.data });
|
dispatch({ type: DEVICETYPE_DATA_RECEIVED, payload: devicetypesResponse.data });
|
||||||
axios.get(`${baseURL}/gateways`, { headers: { Authorization: authToken } })
|
axios.get(`${baseURL}/gateways`, { headers: { Authorization: authToken } })
|
||||||
.then((gtwResponse) => {
|
.then((gtwResponse) => {
|
||||||
dispatch({ type: GATEWAY_DATA_RECEIVED, payload: gtwResponse.data });
|
dispatch({ type: GATEWAY_DATA_RECEIVED, payload: gtwResponse.data });
|
||||||
@@ -32,3 +32,5 @@ export const getData = ({ authToken }) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const dummy = '';
|
||||||
|
|
||||||
|
|||||||
BIN
app/src/assets/POCloud.png
Normal file
BIN
app/src/assets/POCloud.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
@@ -1,6 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import pocloudLogo from '../assets/POCloud.png';
|
||||||
|
|
||||||
import { logoutUser } from '../actions';
|
import { logoutUser } from '../actions';
|
||||||
|
|
||||||
@@ -15,38 +16,38 @@ class Header extends Component {
|
|||||||
const { authToken } = this.props.auth;
|
const { authToken } = this.props.auth;
|
||||||
if (authToken) {
|
if (authToken) {
|
||||||
return (
|
return (
|
||||||
<nav>
|
<nav className="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
<div className="nav-wrapper">
|
<span className="navbar-brand mb-0 h1">
|
||||||
<ul className="right">
|
<img src={pocloudLogo} className="img-fluid" alt="POCloud" style={{ maxWidth: 200 }} />
|
||||||
<li>
|
</span>
|
||||||
<button
|
|
||||||
className="btn waves-effect waves-light"
|
<ul className="navbar-nav mr-auto">
|
||||||
onClick={this.onLogoutButtonClicked.bind(this)}
|
<li className="nav-item">
|
||||||
style={{ marginRight: 15 }}
|
<Link to="/main" className="nav-link">Main</Link>
|
||||||
>
|
</li>
|
||||||
Log Out
|
</ul>
|
||||||
</button>
|
|
||||||
</li>
|
<button
|
||||||
</ul>
|
className="btn btn-danger"
|
||||||
<ul>
|
onClick={this.onLogoutButtonClicked.bind(this)}
|
||||||
<li>
|
>
|
||||||
<Link to="/main">Main</Link>
|
Log Out
|
||||||
</li>
|
</button>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav>
|
<nav className="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
<div className="nav-wrapper">
|
<span className="navbar-brand mb-0 h1">
|
||||||
<ul>
|
<img src={pocloudLogo} className="img-fluid" alt="POCloud" style={{ maxWidth: 200 }} />
|
||||||
<li>
|
</span>
|
||||||
<Link to="/login">Login</Link>
|
|
||||||
</li>
|
<ul className="navbar-nav mr-auto">
|
||||||
</ul>
|
<li className="nav-item">
|
||||||
</div>
|
<Link to="/login" className="nav-link">Login</Link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ import { connect } from 'react-redux';
|
|||||||
import { emailChanged, passwordChanged, loginUser } from '../actions';
|
import { emailChanged, passwordChanged, loginUser } from '../actions';
|
||||||
|
|
||||||
class Login extends Component {
|
class Login extends Component {
|
||||||
|
componentWillMount() {
|
||||||
|
if (this.props.auth.authToken) {
|
||||||
|
this.props.history.push('/main');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onEmailChange(event) {
|
onEmailChange(event) {
|
||||||
this.props.emailChanged(event.target.value);
|
this.props.emailChanged(event.target.value);
|
||||||
}
|
}
|
||||||
@@ -19,46 +25,57 @@ class Login extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { email, password, authToken } = this.props.auth;
|
const { email, password } = this.props.auth;
|
||||||
if (authToken) {
|
|
||||||
this.props.history.push('/main');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="container">
|
||||||
<h1>Login</h1>
|
<div className="row">
|
||||||
<form className="col s12">
|
<div className="col">
|
||||||
<div className="input-field col s12">
|
<h1>Login</h1>
|
||||||
<input
|
<form>
|
||||||
placeholder="email@email.com"
|
<div className="form-group">
|
||||||
id="email"
|
<label htmlFor="email">Email Address</label>
|
||||||
type="email"
|
<input
|
||||||
value={email}
|
type="email"
|
||||||
onChange={this.onEmailChange.bind(this)}
|
className="form-control"
|
||||||
/>
|
id="email"
|
||||||
<label htmlFor="email">Email Address</label>
|
aria-describedby="emailHelp"
|
||||||
|
placeholder="email@website.com"
|
||||||
|
value={email}
|
||||||
|
onChange={this.onEmailChange.bind(this)}
|
||||||
|
/>
|
||||||
|
<small
|
||||||
|
id="emailHelp"
|
||||||
|
className="form-text text-muted"
|
||||||
|
>
|
||||||
|
Enter your POCloud login information.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="password">Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
className="form-control"
|
||||||
|
id="password"
|
||||||
|
value={password}
|
||||||
|
onChange={this.onPasswordChange.bind(this)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="btn waves-effect waves-light"
|
||||||
|
type="submit"
|
||||||
|
name="action"
|
||||||
|
onClick={this.onButtonPress.bind(this)}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="input-field col s12">
|
|
||||||
<input
|
|
||||||
id="password"
|
|
||||||
type="password"
|
|
||||||
value={password}
|
|
||||||
onChange={this.onPasswordChange.bind(this)}
|
|
||||||
/>
|
|
||||||
<label htmlFor="password">Password</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
className="btn waves-effect waves-light"
|
|
||||||
type="submit"
|
|
||||||
name="action"
|
|
||||||
onClick={this.onButtonPress.bind(this)}
|
|
||||||
>
|
|
||||||
Submit <i className="material-icons right">send</i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,143 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { getData } from '../actions';
|
import { getData } from '../actions';
|
||||||
|
|
||||||
class Main extends Component {
|
class Main extends Component {
|
||||||
componentWillMount() {
|
state = {
|
||||||
this.props.getData();
|
companyShowingDetails: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
const { authToken } = this.props.auth;
|
||||||
|
this.props.getData({ authToken });
|
||||||
|
}
|
||||||
|
|
||||||
|
getGatewaysForCompany({ companyId }) {
|
||||||
|
return _.filter(this.props.gateways, g => g.companyId === companyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDevicesForGateway({ gatewayId }) {
|
||||||
|
return _.filter(this.props.allDevices, g => g.gatewayId === gatewayId);
|
||||||
|
}
|
||||||
|
|
||||||
|
companySelected({ companyId }) {
|
||||||
|
if (companyId === this.state.companyShowingDetails) {
|
||||||
|
this.setState({ companyShowingDetails: 0 });
|
||||||
|
} else {
|
||||||
|
this.setState({ companyShowingDetails: companyId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderGatewayList({ gatewayId }) {
|
||||||
|
const devices = this.getDevicesForGateway({ gatewayId });
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{_.map(devices, d => (
|
||||||
|
<li key={d.id}>{d.vanityName} - {this.props.devicetypes[d.deviceTypeId].vanityName}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCompanyGatewayList({ gatewayList }) {
|
||||||
|
return _.map(gatewayList, g => (
|
||||||
|
<tr>
|
||||||
|
<th>{g.name}</th>
|
||||||
|
<th>{g.macAddress}</th>
|
||||||
|
</tr>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
renderCompanyTable({ companyId }) {
|
||||||
|
const gateways = this.getGatewaysForCompany({ companyId });
|
||||||
|
let gatewayList;
|
||||||
|
|
||||||
|
if (companyId === this.state.companyShowingDetails) {
|
||||||
|
gatewayList = (
|
||||||
|
<table className="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Gateway</th>
|
||||||
|
<th>MAC Address</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{this.renderCompanyGatewayList({ gatewayList: gateways })}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gateways.length > 0) {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={companyId}
|
||||||
|
className="list-group-item flex-column align-items-center"
|
||||||
|
onClick={() => this.companySelected({ companyId })}
|
||||||
|
>
|
||||||
|
<div className="d-flex justify-content-between">
|
||||||
|
{this.props.companies[companyId].name}
|
||||||
|
<span className="badge badge-primary badge-pill">{gateways.length}</span>
|
||||||
|
</div>
|
||||||
|
{gatewayList}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<h1>Meshify Devices</h1>
|
<div className="container">
|
||||||
<table>
|
<div className="row">
|
||||||
<thead>
|
<div className="col">
|
||||||
|
<h1>Companies with Devices</h1>
|
||||||
|
<ul className="list-group">
|
||||||
|
{_.map(this.props.companies, c => this.renderCompanyTable({ companyId: c.id }))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</thead>
|
<div className="row">
|
||||||
</table>
|
<div className="col">
|
||||||
|
<h1>Companies with NO Devices</h1>
|
||||||
|
<ul className="list-group" style={{ marginBottom: 20 }}>
|
||||||
|
{_.map(this.props.companies, c => {
|
||||||
|
if (this.getGatewaysForCompany({ companyId: c.id }).length === 0) {
|
||||||
|
return (
|
||||||
|
<li className="list-group-item">
|
||||||
|
{this.props.companies[c.id].name}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
const mapStateToProps = (state) => {
|
||||||
|
console.log(state.meshify);
|
||||||
|
const {
|
||||||
|
gateways,
|
||||||
|
devicetypes,
|
||||||
|
allDevices,
|
||||||
|
companies,
|
||||||
|
devices,
|
||||||
|
} = state.meshify;
|
||||||
return {
|
return {
|
||||||
auth: state.auth,
|
auth: state.auth,
|
||||||
|
gateways,
|
||||||
|
devicetypes,
|
||||||
|
allDevices,
|
||||||
|
companies,
|
||||||
|
devices,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import _ from 'lodash';
|
|
||||||
import {
|
import {
|
||||||
EMAIL_CHANGED,
|
EMAIL_CHANGED,
|
||||||
PASSWORD_CHANGED,
|
PASSWORD_CHANGED,
|
||||||
@@ -6,7 +5,6 @@ import {
|
|||||||
LOGIN_USER_SUCCESS,
|
LOGIN_USER_SUCCESS,
|
||||||
LOGIN_USER_FAIL,
|
LOGIN_USER_FAIL,
|
||||||
LOGOUT,
|
LOGOUT,
|
||||||
COMPANY_DATA_RECEIVED,
|
|
||||||
} from '../actions/types';
|
} from '../actions/types';
|
||||||
|
|
||||||
const INITIAL_STATE = {
|
const INITIAL_STATE = {
|
||||||
@@ -53,15 +51,6 @@ export default (state = INITIAL_STATE, action) => {
|
|||||||
case LOGOUT:
|
case LOGOUT:
|
||||||
return INITIAL_STATE;
|
return INITIAL_STATE;
|
||||||
|
|
||||||
case COMPANY_DATA_RECEIVED:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
user: {
|
|
||||||
...state.user,
|
|
||||||
companyName: _.keyBy(action.payload, c => c.id)[state.user.companyId].name,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { combineReducers } from 'redux';
|
import { combineReducers } from 'redux';
|
||||||
import AuthReducer from './authReducer';
|
import AuthReducer from './authReducer';
|
||||||
|
import MeshifyReducer from './meshifyReducer';
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
auth: AuthReducer,
|
auth: AuthReducer,
|
||||||
|
meshify: MeshifyReducer,
|
||||||
});
|
});
|
||||||
|
|||||||
45
app/src/reducers/meshifyReducer.js
Normal file
45
app/src/reducers/meshifyReducer.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import {
|
||||||
|
GATEWAY_DATA_RECEIVED,
|
||||||
|
DEVICETYPE_DATA_RECEIVED,
|
||||||
|
DEVICE_DATA_RECEIVED,
|
||||||
|
COMPANY_DATA_RECEIVED,
|
||||||
|
} from '../actions/types';
|
||||||
|
|
||||||
|
const INITIAL_STATE = {
|
||||||
|
gateways: {},
|
||||||
|
devicetypes: {},
|
||||||
|
allDevices: {},
|
||||||
|
companies: {},
|
||||||
|
devices: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (state = INITIAL_STATE, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case GATEWAY_DATA_RECEIVED:
|
||||||
|
return { ...state, gateways: _.keyBy(action.payload, g => g.id) };
|
||||||
|
|
||||||
|
case COMPANY_DATA_RECEIVED:
|
||||||
|
return { ...state, companies: _.keyBy(action.payload, c => c.id) };
|
||||||
|
|
||||||
|
case DEVICETYPE_DATA_RECEIVED:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
devicetypes: _.keyBy(action.payload, d => d.id),
|
||||||
|
};
|
||||||
|
|
||||||
|
case DEVICE_DATA_RECEIVED:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
devices: _.groupBy(action.payload, (device) => {
|
||||||
|
if (state.devicetypes[device.deviceTypeId]) {
|
||||||
|
return state.devicetypes[device.deviceTypeId].id;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
allDevices: _.keyBy(action.payload, d => d.id),
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
853
package-lock.json
generated
853
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
|||||||
},
|
},
|
||||||
"author": "Patric McDonagh",
|
"author": "Patric McDonagh",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint-config-airbnb": "^16.1.0",
|
"electron": "^2.0.2",
|
||||||
"npm-run-all": "^4.1.3",
|
"npm-run-all": "^4.1.3",
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-eslint": "^8.2.2",
|
"babel-eslint": "^8.2.2",
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"base-64": "^0.1.0",
|
"base-64": "^0.1.0",
|
||||||
"electron": "^2.0.2",
|
|
||||||
"electron-localshortcut": "^1.1.1",
|
"electron-localshortcut": "^1.1.1",
|
||||||
|
"eslint-config-rallycoding": "^3.2.0",
|
||||||
"lodash": "^4.17.10",
|
"lodash": "^4.17.10",
|
||||||
"moment": "^2.18.1",
|
"moment": "^2.18.1",
|
||||||
"moment-duration-format": "^1.3.0",
|
"moment-duration-format": "^1.3.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user