working on lots of compiler errors and lint errors, added . eslint and prettier configs for formating

This commit is contained in:
Dakota Peel 2020-05-17 23:01:07 -04:00
parent b27e5fa408
commit 12cbcd8e00
62 changed files with 1940 additions and 1994 deletions

2
.env
View File

@ -1 +1 @@
NODE_PATH=./ledfx/
NODE_PATH=./frontend/

View File

@ -13,12 +13,6 @@ module.exports = {
'react',
'@typescript-eslint',
'prettier',
// "jsx-a11y",
// 'import',
// 'import-order-autofix',
// 'sort-keys-fix',
// 'sort-destructure-keys',
// '@typescript-eslint/eslint',
],
globals: {
__DEV__: false,
@ -35,62 +29,6 @@ module.exports = {
},
rules: {
'prettier/prettier': 'error',
// 'comma-dangle': 'off',
// 'array-element-newline': ['error', 'consistent'],
// 'array-bracket-spacing': ['error', 'always'],
// 'arrow-parens': ['error', 'as-needed', { requireForBlockBody: false }],
// 'import/order': [
// 'error',
// {
// groups: [['builtin', 'external', 'internal'], ['parent', 'sibling'], 'index'],
// 'newlines-between': 'always',
// },
// ],
// 'sort-imports': [
// 'off',
// {
// ignoreCase: true,
// ignoreMemberSort: false,
// memberSyntaxSortOrder: ['none', 'multiple', 'single', 'all'],
// },
// ],
// 'sort-keys-fix/sort-keys-fix': [
// 'off',
// 'asc',
// {
// caseSensitive: false,
// natural: false,
// },
// ],
// 'react/jsx-sort-default-props': ['warn', { ignoreCase: true }],
// 'import/no-extraneous-dependencies': 'warn',
// 'import/prefer-default-export': ['warn'],
// 'import/no-unresolved': 'off',
// indent: ['warn', 4],
// 'no-multi-spaces': ['error', { exceptions: { ImportDeclaration: true } }],
// 'no-plusplus': 'off',
// 'no-restricted-syntax': ['error', 'ForInStatement', 'LabeledStatement', 'WithStatement'],
'no-shadow': 'off',
// 'no-underscore-dangle': 'off',
// 'no-unused-expressions': ['error', { allowShortCircuit: true }],
// 'no-use-before-define': 'off',
// 'object-property-newline': 'warn',
// 'react/forbid-prop-types': 'off',
// 'react/jsx-filename-extension': ['error', { extensions: ['.js'] }],
// 'react/jsx-first-prop-new-line': ['error', 'multiline'],
// 'react/jsx-indent': ['warn', 4],
// 'react/jsx-indent-props': ['warn', 4],
// 'react/no-unused-prop-types': 'warn',
// 'react/prefer-stateless-function': 'warn',
// 'react/jsx-one-expression-per-line': 'error',
// 'react/sort-prop-types': 'error',
// 'react/jsx-pascal-case': 'error',
// 'react/jsx-fragments': 'off',
// 'react/jsx-max-props-per-line': ['error', { maximum: 1 }],
// 'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
// 'react/jsx-wrap-multilines': ['error'],
// 'sort-destructure-keys/sort-destructure-keys': 'error',
// 'no-param-reassign': 'off',
},
};

View File

@ -1,23 +1,28 @@
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"name": "ledfx",
"version": "0.2.0",
"description": "LedFx",
"author": "Austin Hodges",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/ahodges9/ledfx.git"
},
"dependencies": {
"@material-ui/core": "^4.8.3",
"@material-ui/icons": "^4.5.1",
"@material-ui/core": "^4.9.14",
"@material-ui/icons": "^4.9.1",
"axios": "^0.19.2",
"chart.js": "^2.9.3",
"core-js": "^3.4.1",
"cross-fetch": "^3.0.4",
"core-js": "^3.6.5",
"glob": "^7.1.6",
"history": "^4.10.1",
"react": "^16.13.1",
"react-chartjs-2": "^2.9.0",
"react-dom": "^16.13.1",
"react-event-listener": "^0.6.6",
"react-redux": "^5.1.2",
"react-redux": "^7.2.0",
"react-router-dom": "^4.3.1",
"react-schema-form": "^0.6.15",
"react-schema-form": "^0.8.7",
"recompose": "^0.30.0",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
@ -51,16 +56,17 @@
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"react-scripts": "3.4.1",
"@typescript-eslint/eslint-plugin": "^2.18.0",
"@typescript-eslint/parser": "^2.18.0",
"@typescript-eslint/eslint-plugin": "^2.33.0",
"@typescript-eslint/parser": "^2.33.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-config-prettier": "^6.11.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "^7.18.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-react": "^7.20.0",
"prettier": "^1.19.1",
"typescript": "^3.7.5"
}
"typescript": "^3.9.2"
},
"proxy": "http://127.0.0.1:8888/"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -2,14 +2,17 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- <link rel="stylesheet" type="text/css" href="{{ url('static', filename='./style.css') }}"/> -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"/>
<!-- Mobile App Support -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<link rel="apple-touch-icon" href="%PUBLIC_URL%/ledfx_icon.png" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
@ -24,7 +27,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>LedFx</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,6 +1,6 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"short_name": "Led FX",
"name": "Led FX",
"icons": [
{
"src": "favicon.ico",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,174 +1,145 @@
import fetch from "cross-fetch";
import * as deviceProxies from 'proxies/device';
const apiUrl = window.location.protocol + "//" + window.location.host + "/api";
export const REQUEST_DEVICE_LIST = "REQUEST_DEVICE_LIST";
export const RECEIVE_DEVICE_LIST = "RECEIVE_DEVICE_LIST";
export const RECEIVE_DEVICE_ENTRY = "RECEIVE_DEVICE_ENTRY";
export const REQUEST_DEVICE_UPDATE = "REQUEST_DEVICE_UPDATE";
export const RECEIVE_DEVICE_UPDATE = "RECEIVE_DEVICE_UPDATE";
export const RECEIVE_DEVICE_EFFECT_UPDATE = "RECEIVE_DEVICE_EFFECT_UPDATE";
export const INVALIDATE_DEVICE = "INVALIDATE_DEVICE";
export const SET_DEVICE_EFFECT = "SET_DEVICE_EFFECT";
export const REQUEST_DEVICE_LIST = 'REQUEST_DEVICE_LIST';
export const RECEIVE_DEVICE_LIST = 'RECEIVE_DEVICE_LIST';
export const RECEIVE_DEVICE_ENTRY = 'RECEIVE_DEVICE_ENTRY';
export const REQUEST_DEVICE_UPDATE = 'REQUEST_DEVICE_UPDATE';
export const RECEIVE_DEVICE_UPDATE = 'RECEIVE_DEVICE_UPDATE';
export const RECEIVE_DEVICE_EFFECT_UPDATE = 'RECEIVE_DEVICE_EFFECT_UPDATE';
export const INVALIDATE_DEVICE = 'INVALIDATE_DEVICE';
export const SET_DEVICE_EFFECT = 'SET_DEVICE_EFFECT';
function requestDeviceList() {
return {
type: REQUEST_DEVICE_LIST
};
return {
type: REQUEST_DEVICE_LIST,
};
}
function receiveDeviceList(json) {
return {
type: RECEIVE_DEVICE_LIST,
devices: json.devices,
receivedAt: Date.now()
};
return {
type: RECEIVE_DEVICE_LIST,
devices: json.devices,
receivedAt: Date.now(),
};
}
function receiveDevice(json) {
return {
type: RECEIVE_DEVICE_ENTRY,
device: json.device,
delete: json.delete,
receivedAt: Date.now()
};
}
export function getSystemConfig() {
return fetch(`${apiUrl}/config`)
.then(response => response.json());
return {
type: RECEIVE_DEVICE_ENTRY,
device: json.device,
delete: json.delete,
receivedAt: Date.now(),
};
}
export function addDevice(type, config) {
return dispatch => {
const data = {
type: type,
config: config
return dispatch => {
const data = {
type: type,
config: config,
};
deviceProxies.createDevice(data).then(response => dispatch(receiveDevice(response.data)));
};
fetch(`${apiUrl}/devices`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(json => dispatch(receiveDevice(json)));
};
}
export function deleteDevice(id) {
let deleteJson = { delete: true, device: {id: id} }
let deleteJson = { delete: true, device: { id: id } };
return dispatch => {
fetch(`${apiUrl}/devices/${id}`, {
method: 'DELETE'})
.then(response => dispatch(receiveDevice(deleteJson)));
}
deviceProxies.deleteDevice(id).then(response => dispatch(receiveDevice(deleteJson)));
};
}
export function fetchDeviceList() {
return dispatch => {
dispatch(requestDeviceList());
return fetch(`${apiUrl}/devices`)
.then(response => response.json())
.then(json => dispatch(receiveDeviceList(json)));
};
return dispatch => {
dispatch(requestDeviceList());
return deviceProxies.getDevices().then(response => {
console.log('waht ths devies response', response);
dispatch(receiveDeviceList(response));
});
};
}
export function setDeviceEffect(deviceId, effectType, effectConfig) {
return dispatch => {
if (effectType)
{
fetch(`${apiUrl}/devices/${deviceId}/effects`, {
method: "PUT",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
type: effectType,
config: effectConfig
})
})
.then(response => response.json())
.then(json => dispatch(receiveDeviceEffectUpdate(deviceId, json)));
}
else
{
fetch(`${apiUrl}/devices/${deviceId}/effects`, {
method: "DELETE"
})
.then(response => response.json())
.then(json => dispatch(receiveDeviceEffectUpdate(deviceId, json)));
}
};
return dispatch => {
if (effectType) {
deviceProxies
.getDeviceEffects(deviceId, {
type: effectType,
config: effectConfig,
})
.then(response => dispatch(receiveDeviceEffectUpdate(deviceId, response.data)));
} else {
deviceProxies
.deleteDeviceEffects(deviceId)
.then(response => dispatch(receiveDeviceEffectUpdate(deviceId, response.data)));
}
};
}
function invalidateDevice(deviceId) {
return {
type: INVALIDATE_DEVICE,
deviceId
};
return {
type: INVALIDATE_DEVICE,
deviceId,
};
}
function requestDeviceUpdate(deviceId) {
return {
type: REQUEST_DEVICE_UPDATE,
deviceId
};
return {
type: REQUEST_DEVICE_UPDATE,
deviceId,
};
}
function receiveDeviceUpdate(deviceId, json) {
return {
type: RECEIVE_DEVICE_UPDATE,
deviceId,
config: json.config.map(config => config),
receivedAt: Date.now()
};
return {
type: RECEIVE_DEVICE_UPDATE,
deviceId,
config: json.config.map(config => config),
receivedAt: Date.now(),
};
}
function receiveDeviceEffectUpdate(deviceId, json) {
return {
type: RECEIVE_DEVICE_EFFECT_UPDATE,
deviceId,
effect: json.effect,
receivedAt: Date.now()
};
return {
type: RECEIVE_DEVICE_EFFECT_UPDATE,
deviceId,
effect: json.effect,
receivedAt: Date.now(),
};
}
function fetchDevice(deviceId) {
return dispatch => {
dispatch(requestDeviceUpdate(deviceId));
return fetch(`${apiUrl}/devices/${deviceId}`)
.then(response => response.json())
.then(json => dispatch(receiveDeviceUpdate(deviceId, json)))
};
return dispatch => {
dispatch(requestDeviceUpdate(deviceId));
return deviceProxies
.getDevice(deviceId)
.then(response => dispatch(receiveDeviceUpdate(deviceId, response.data)));
};
}
export function fetchDeviceEffects(deviceId) {
return dispatch => {
return fetch(`${apiUrl}/devices/${deviceId}/effects`)
.then(response => response.json())
.then(json => dispatch(receiveDeviceEffectUpdate(deviceId, json)));
};
return dispatch => {
return deviceProxies
.getDeviceEffects(deviceId)
.then(response => dispatch(receiveDeviceEffectUpdate(deviceId, response.data)));
};
}
function shouldFetchDevice(state, deviceId) {
const device = state.devicesById[deviceId];
if (!device) {
return true;
} else if (device.isFetching) {
return false;
} else {
return device.didInvalidate;
}
const device = state.devicesById[deviceId];
if (!device) {
return true;
} else if (device.isFetching) {
return false;
} else {
return device.didInvalidate;
}
}
export function fetchDeviceIfNeeded(deviceId) {
return (dispatch, getState) => {
if (shouldFetchDevice(getState(), deviceId)) {
return dispatch(fetchDevice(deviceId));
}
};
return (dispatch, getState) => {
if (shouldFetchDevice(getState(), deviceId)) {
return dispatch(fetchDevice(deviceId));
}
};
}

View File

@ -1,117 +1,84 @@
import fetch from "cross-fetch";
import { api } from 'utils/api';
const apiUrl = window.location.protocol + "//" + window.location.host + "/api";
export const ADD_PRESET = "ADD_PRESET"
export const DELETE_PRESET = "DELETE_PRESET"
export const GET_PRESETS = "GET_PRESETS"
export const ACTIVATE_PRESET = "ACTIVATE_PRESET"
export const RENAME_PRESET = "RENAME_PRESET"
export const ADD_PRESET = 'ADD_PRESET';
export const DELETE_PRESET = 'DELETE_PRESET';
export const GET_PRESETS = 'GET_PRESETS';
export const ACTIVATE_PRESET = 'ACTIVATE_PRESET';
export const RENAME_PRESET = 'RENAME_PRESET';
export function addPreset(name) {
return dispatch => {
const data = {
name: name
return dispatch => {
const data = {
name: name,
};
return api
.post('/presets', data)
.then(response =>
dispatch({
type: ADD_PRESET,
response: response.data,
})
)
.then(() => dispatch(getPresets()));
};
return fetch(`${apiUrl}/presets`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(json => dispatch({
type: ADD_PRESET,
response: json
}))
.then(() => dispatch(getPresets()))
};
}
export function deletePreset(id) {
return dispatch => {
const data = {
id: id
return dispatch => {
const data = {
id: id,
};
return api
.delete('/presets', data)
.then(response =>
dispatch({
type: DELETE_PRESET,
response: response.data,
})
)
.then(() => dispatch(getPresets()));
};
return fetch(`${apiUrl}/presets`, {
method: "DELETE",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(json => dispatch({
type: DELETE_PRESET,
response: json
}))
.then(() => dispatch(getPresets()))
};
}
export function activatePreset(id) {
return dispatch => {
const data = {
id: id,
action: 'activate'
return dispatch => {
const data = {
id: id,
action: 'activate',
};
api.put('/presets', data).then(response =>
dispatch({
type: ACTIVATE_PRESET,
response: response.data,
})
);
};
fetch(`${apiUrl}/presets`, {
method: "PUT",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(json => dispatch({
type: ACTIVATE_PRESET,
response: json
}));
};
}
export function renamePreset(id, name) {
return dispatch => {
const data = {
id: id,
action: 'rename',
name: name
return dispatch => {
const data = {
id: id,
action: 'rename',
name: name,
};
api.put('/presets', data).then(response =>
dispatch({
type: RENAME_PRESET,
response: response.data,
})
);
};
fetch(`${apiUrl}/presets`, {
method: "PUT",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(json => dispatch({
type: RENAME_PRESET,
response: json
}));
};
}
export function getPresets() {
return dispatch => {
fetch(`${apiUrl}/presets`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
})
.then(response => response.json())
.then(json => dispatch({
type: GET_PRESETS,
presets: json.presets,
receivedAt: Date.now()
}))
}
return dispatch => {
api.get('/presets').then(response =>
dispatch({
type: GET_PRESETS,
presets: response.data.presets,
receivedAt: Date.now(),
})
);
};
}

View File

@ -1,45 +1,41 @@
import fetch from "cross-fetch";
import { api } from 'utils/api';
const apiUrl = window.location.protocol + "//" + window.location.host + "/api";
export const REQUEST_SCHEMAS = "REQUEST_SCHEMAS";
export const RECEIVE_SCHEMAS = "RECEIVE_SCHEMAS";
export const REQUEST_SCHEMAS = 'REQUEST_SCHEMAS';
export const RECEIVE_SCHEMAS = 'RECEIVE_SCHEMAS';
function requestSchemas() {
return {
type: REQUEST_SCHEMAS
};
return {
type: REQUEST_SCHEMAS,
};
}
function receiveSchemas(json) {
return {
type: RECEIVE_SCHEMAS,
schemas: json,
receivedAt: Date.now()
};
return {
type: RECEIVE_SCHEMAS,
schemas: json,
receivedAt: Date.now(),
};
}
function fetchSchemas() {
return dispatch => {
dispatch(requestSchemas());
return fetch(`${apiUrl}/schema`)
.then(response => response.json())
.then(json => dispatch(receiveSchemas(json)));
};
return dispatch => {
dispatch(requestSchemas());
return api.get(`/schema`).then(response => dispatch(receiveSchemas(response.data)));
};
}
function shouldFetchSchemas(state) {
if (Object.keys(state.schemas).length === 0) {
return true;
} else {
return false;
}
if (Object.keys(state.schemas).length === 0) {
return true;
} else {
return false;
}
}
export function fetchSchemasIfNeeded() {
return (dispatch, getState) => {
if (shouldFetchSchemas(getState())) {
return dispatch(fetchSchemas());
}
};
return (dispatch, getState) => {
if (shouldFetchSchemas(getState())) {
return dispatch(fetchSchemas());
}
};
}

View File

@ -1,45 +1,32 @@
const apiUrl = window.location.protocol + "//" + window.location.host + "/api";
import { api } from 'utils/api';
export const GET_AUDIO_INPUTS = "GET_AUDIO_INPUTS"
export const SET_AUDIO_INPUT = "GET_AUDIO_INPUT"
export const GET_AUDIO_INPUTS = 'GET_AUDIO_INPUTS';
export const SET_AUDIO_INPUT = 'GET_AUDIO_INPUT';
export function setAudioDevice(index) {
return dispatch => {
const data = {
index: parseInt(index)
return dispatch => {
const data = {
index: parseInt(index),
};
api.put('/audio/devices', data)
.then(response =>
dispatch({
type: SET_AUDIO_INPUT,
response: response.data,
})
)
.then(() => dispatch(getAudioDevices()));
};
fetch(`${apiUrl}/audio/devices`, {
method: "PUT",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(json => dispatch({
type: SET_AUDIO_INPUT,
response: json
}))
.then(() => dispatch(getAudioDevices()));
};
}
export function getAudioDevices() {
return dispatch => {
fetch(`${apiUrl}/audio/devices`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
})
.then(response => response.json())
.then(json => dispatch({
type: GET_AUDIO_INPUTS,
audioDevices: json,
receivedAt: Date.now()
}))
}
return dispatch => {
api.get('/audio/devices').then(response =>
dispatch({
type: GET_AUDIO_INPUTS,
audioDevices: response.data,
receivedAt: Date.now(),
})
);
};
}

View File

@ -1,6 +1,5 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux'
import { connect } from 'react-redux';
import { makeStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
@ -11,60 +10,58 @@ import Button from '@material-ui/core/Button';
import { addPreset } from '../../actions';
const useStyles = makeStyles({
button: {
display: "block",
width: "100",
float: "right"
},
action: {
padding: "0"
}
const useStyles = makeStyles({
button: {
display: 'block',
width: '100',
float: 'right',
},
action: {
padding: '0',
},
});
const AddPresetCard = ({ presets, addPreset }) => {
const AddPresetCard = ({ presets, addPreset }) => {
const [name, setName] = useState('');
const classes = useStyles();
const [ name, setName ] = useState('')
const classes = useStyles()
return (
<Card>
<CardContent>
<h3>Add Preset</h3>
Save current effects of all devices as a preset
<CardActions className = {classes.action}>
<TextField
error = {validateInput(name, presets)}
id="presetNameInput"
label="Preset Name"
onChange={(e) => setName(e.target.value)}
/>
<Button
className = {classes.button}
color="primary"
size="small"
aria-label="Save"
disabled = {validateInput(name, presets)}
variant = "contained"
onClick = {() => addPreset(name)}
>
Save
</Button>
</CardActions>
</CardContent>
</Card>
return (
<Card>
<CardContent>
<h3>Add Preset</h3>
Save current effects of all devices as a preset
<CardActions className={classes.action}>
<TextField
error={validateInput(name, presets)}
id="presetNameInput"
label="Preset Name"
onChange={e => setName(e.target.value)}
/>
<Button
className={classes.button}
color="primary"
size="small"
aria-label="Save"
disabled={validateInput(name, presets)}
variant="contained"
onClick={() => addPreset(name)}
>
Save
</Button>
</CardActions>
</CardContent>
</Card>
);
}
};
const validateInput = (input, presets) => (Object.keys(presets).includes(input) || input === "")
const validateInput = (input, presets) => Object.keys(presets).includes(input) || input === '';
const mapStateToProps = state => ({
presets: state.presets
})
const mapStateToProps = state => ({
presets: state.presets,
});
const mapDispatchToProps = (dispatch) => ({
addPreset: (presetName) => dispatch(addPreset(presetName))
})
const mapDispatchToProps = dispatch => ({
addPreset: presetName => dispatch(addPreset(presetName)),
});
export default connect(mapStateToProps, mapDispatchToProps)(AddPresetCard);
export default connect(mapStateToProps, mapDispatchToProps)(AddPresetCard);

View File

@ -1,87 +1,75 @@
import React from "react";
import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles";
import { connect } from "react-redux";
import React from 'react';
import withStyles from '@material-ui/core/styles/withStyles';
import { connect } from 'react-redux';
import Button from "@material-ui/core/Button";
import Dialog from "@material-ui/core/Dialog";
import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle";
import DialogActions from "@material-ui/core/DialogActions";
import DialogContentText from "@material-ui/core/DialogContentText";
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContentText from '@material-ui/core/DialogContentText';
import SchemaFormCollection from "../../components/SchemaForm/SchemaFormCollection.jsx";
import { addDevice } from"../../actions";
import fetch from "cross-fetch";
import SchemaFormCollection from 'components/SchemaForm/SchemaFormCollection.jsx';
import { addDevice } from 'actions';
const styles = theme => ({
button: {
float: "right"
}
button: {
float: 'right',
},
});
class DeviceConfigDialog extends React.Component {
constructor(props) {
super(props);
}
handleClose = () => {
this.props.onClose();
};
handleClose = () => {
this.props.onClose();
};
handleSubmit = (type, config) => {
this.props.dispatch(addDevice(type, config));
this.props.onClose();
};
handleSubmit = (type, config) => {
this.props.dispatch(addDevice(type, config));
this.props.onClose();
};
render() {
const { classes, dispatch, schemas, onClose, ...otherProps } = this.props;
return (
<Dialog
onClose={this.handleClose}
className={classes.cardResponsive}
aria-labelledby="form-dialog-title"
{...otherProps}
>
<DialogTitle id="form-dialog-title">Add Device</DialogTitle>
<DialogContent className={classes.cardResponsive}>
<DialogContentText>
To add a device to LedFx, please first select the type of device you
wish to add then provide the necessary configuration.
</DialogContentText>
<SchemaFormCollection
schemaCollection={schemas.devices}
onSubmit={this.handleSubmit}
useAdditionalProperties={true}
>
<Button
className={classes.button}
type="submit"
color="primary"
render() {
const { classes, dispatch, schemas, onClose, ...otherProps } = this.props;
return (
<Dialog
onClose={this.handleClose}
className={classes.cardResponsive}
aria-labelledby="form-dialog-title"
{...otherProps}
>
Add
</Button>
<Button
className={classes.button}
onClick={this.handleClose}
color="primary"
>
Cancel
</Button>
</SchemaFormCollection>
</DialogContent>
</Dialog>
);
}
<DialogTitle id="form-dialog-title">Add Device</DialogTitle>
<DialogContent className={classes.cardResponsive}>
<DialogContentText>
To add a device to LedFx, please first select the type of device you wish to
add then provide the necessary configuration.
</DialogContentText>
<SchemaFormCollection
schemaCollection={schemas.devices}
onSubmit={this.handleSubmit}
useAdditionalProperties={true}
>
<Button className={classes.button} type="submit" color="primary">
Add
</Button>
<Button
className={classes.button}
onClick={this.handleClose}
color="primary"
>
Cancel
</Button>
</SchemaFormCollection>
</DialogContent>
</Dialog>
);
}
}
function mapStateToProps(state) {
const { schemas } = state;
const { schemas } = state;
return {
schemas
};
return {
schemas,
};
}
export default connect(mapStateToProps)(withStyles(styles)(DeviceConfigDialog));

View File

@ -1,107 +1,100 @@
import React from "react";
import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles";
import { connect } from "react-redux";
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import { connect } from 'react-redux';
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import Button from '@material-ui/core/Button';
import Switch from '@material-ui/core/Switch';
import TableRow from '@material-ui/core/TableRow';
import TableCell from '@material-ui/core/TableCell';
import Grid from "@material-ui/core/Grid";
import Typography from "@material-ui/core/Typography";
import { NavLink } from "react-router-dom";
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { NavLink } from 'react-router-dom';
import { setDeviceEffect } from "../../actions";
import { setDeviceEffect } from '../../actions';
const styles = theme => ({
button: {
margin: theme.spacing.unit,
float: "right"
},
submitControls: {
margin: theme.spacing.unit,
display: "block",
width: "100%"
},
tableCell: {
lineHeight: "1.2",
padding: "12px 8px",
verticalAlign: "middle"
},
deviceLink: {
textDecoration: "none",
"&,&:hover": {
color: "#000000"
}
},
header: {
margin: 0
},
subHeader: {
margin: 0,
color: "#333333"
}
button: {
margin: theme.spacing.unit,
float: 'right',
},
submitControls: {
margin: theme.spacing.unit,
display: 'block',
width: '100%',
},
tableCell: {
lineHeight: '1.2',
padding: '12px 8px',
verticalAlign: 'middle',
},
deviceLink: {
textDecoration: 'none',
'&,&:hover': {
color: '#000000',
},
},
header: {
margin: 0,
},
subHeader: {
margin: 0,
color: '#333333',
},
});
class DeviceMiniControl extends React.Component {
isDeviceOn = () => {
return this.props.device.effect && this.props.device.effect.name;
};
isDeviceOn = () => {
return this.props.device.effect && this.props.device.effect.name;
}
toggleOn = () => {
if (this.isDeviceOn()) {
this.props.dispatch(setDeviceEffect(this.props.device.id, null, null));
} else {
this.props.dispatch(setDeviceEffect(this.props.device.id, 'wavelength', null));
}
};
toggleOn = () => {
if (this.isDeviceOn())
{
this.props.dispatch(setDeviceEffect(this.props.device.id, null, null));
}
else
{
this.props.dispatch(setDeviceEffect(this.props.device.id, 'wavelength', null));
}
}
render() {
const { classes, device } = this.props;
render() {
const { classes, device } = this.props;
return (
<Grid container direction="col" spacing={1}>
<Grid item xs>
<Typography variant="h5" color="inherit" className={classes.header}>
{device.config.name}
</Typography>
<Typography variant="caption text" color="inherit" className={classes.subHeader}>
Effect: {device.effect.name}
</Typography>
</Grid>
{/* <Grid item xs>
return (
<Grid container direction="col" spacing={1}>
<Grid item xs>
<Typography variant="h5" color="inherit" className={classes.header}>
{device.config.name}
</Typography>
<Typography
variant="caption text"
color="inherit"
className={classes.subHeader}
>
Effect: {device.effect.name}
</Typography>
</Grid>
{/* <Grid item xs>
</Grid> */}
<Grid item>
<Button
component={NavLink}
to={'/devices/' + device.id}
className={classes.deviceLink}
key={device.id}>
Change Effect
</Button>
</Grid>
<Grid>
<Switch
checked={this.isDeviceOn()}
onChange={this.toggleOn}
color="primary"/>
</Grid>
</Grid>
);
}
<Grid item>
<Button
component={NavLink}
to={'/devices/' + device.id}
className={classes.deviceLink}
key={device.id}
>
Change Effect
</Button>
</Grid>
<Grid>
<Switch checked={this.isDeviceOn()} onChange={this.toggleOn} color="primary" />
</Grid>
</Grid>
);
}
}
DeviceMiniControl.propTypes = {
classes: PropTypes.object.isRequired,
device: PropTypes.object.isRequired
classes: PropTypes.object.isRequired,
device: PropTypes.object.isRequired,
};
export default connect()(withStyles(styles)(DeviceMiniControl));

View File

@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux'
import { connect } from 'react-redux';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableHead from '@material-ui/core/TableHead';
@ -8,84 +8,88 @@ import TableRow from '@material-ui/core/TableRow';
import TableCell from '@material-ui/core/TableCell';
import TableBody from '@material-ui/core/TableBody';
import DevicesTableItem from '../../components/DevicesTable/DevicesTableItem.jsx'
import { deleteDevice } from '../../actions'
import DevicesTableItem from 'components/DevicesTable/DevicesTableItem.jsx';
import { deleteDevice } from 'actions';
const styles = theme => ({
root: {
width: '100%',
maxWidth: 360,
backgroundColor: theme.palette.background.paper,
},
nested: {
paddingLeft: theme.spacing.unit * 4,
},
table: {
marginBottom: "0",
width: "100%",
maxWidth: "100%",
backgroundColor: "transparent",
borderSpacing: "0",
borderCollapse: "collapse"
},
tableResponsive: {
width: "100%",
overflowX: "auto"
},
tableCell: {
lineHeight: "1.42857143",
padding: "12px 8px",
verticalAlign: "middle"
}
root: {
width: '100%',
maxWidth: 360,
backgroundColor: theme.palette.background.paper,
},
nested: {
paddingLeft: theme.spacing.unit * 4,
},
table: {
marginBottom: '0',
width: '100%',
maxWidth: '100%',
backgroundColor: 'transparent',
borderSpacing: '0',
borderCollapse: 'collapse',
},
tableResponsive: {
width: '100%',
overflowX: 'auto',
},
tableCell: {
lineHeight: '1.42857143',
padding: '12px 8px',
verticalAlign: 'middle',
},
});
class DevicesTable extends React.Component {
handleDeleteDevice = deviceId => {
this.props.dispatch(deleteDevice(deviceId));
};
handleDeleteDevice = deviceId => {
this.props.dispatch(deleteDevice(deviceId))
}
render() {
const { classes, devicesById } = this.props;
render() {
const { classes, devicesById } = this.props;
return (
<div className={classes.tableResponsive}>
<Table className={classes.table}>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell className={classes.tableCell}>IP Address</TableCell>
<TableCell className={classes.tableCell}>Pixel Count</TableCell>
<TableCell className={classes.tableCell}>Type</TableCell>
<TableCell className={classes.tableCell} numeric>
Manage
</TableCell>
</TableRow>
</TableHead>
return (
<div className={classes.tableResponsive}>
<Table className={classes.table}>
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell className={classes.tableCell}>IP Address</TableCell>
<TableCell className={classes.tableCell}>Pixel Count</TableCell>
<TableCell className={classes.tableCell}>Type</TableCell>
<TableCell className={classes.tableCell} numeric>Manage</TableCell>
</TableRow>
</TableHead>
<TableBody>
{
Object.keys(devicesById).map(device_id => {
return (
<DevicesTableItem key={device_id} device={devicesById[device_id]} onDelete={this.handleDeleteDevice}/>
);
})}
</TableBody>
</Table>
</div>
);
}
<TableBody>
{Object.keys(devicesById).map(device_id => {
return (
<DevicesTableItem
key={device_id}
device={devicesById[device_id]}
onDelete={this.handleDeleteDevice}
/>
);
})}
</TableBody>
</Table>
</div>
);
}
}
DevicesTable.propTypes = {
classes: PropTypes.object.isRequired,
devicesById: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
devicesById: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
const { devicesById } = state
const { devicesById } = state;
return {
devicesById
}
return {
devicesById,
};
}
export default connect(mapStateToProps)(withStyles(styles)(DevicesTable));
export default connect(mapStateToProps)(withStyles(styles)(DevicesTable));

View File

@ -1,7 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { NavLink } from "react-router-dom";
import { Link } from 'react-router-dom'
import { NavLink } from 'react-router-dom';
import { withStyles } from '@material-ui/core/styles';
import TableRow from '@material-ui/core/TableRow';
@ -11,74 +10,72 @@ import DeleteIcon from '@material-ui/icons/Delete';
import red from '@material-ui/core/colors/red';
const styles = theme => ({
tableCell: {
lineHeight: "1.42857143",
padding: "12px 8px",
verticalAlign: "middle"
},
button: {
margin: 0,
padding: 0,
minWidth: 32
},
deleteButton: {
minWidth: 32,
color: theme.palette.getContrastText(red[500]),
backgroundColor: red[500],
'&:hover': {
backgroundColor: red[700],
tableCell: {
lineHeight: '1.42857143',
padding: '12px 8px',
verticalAlign: 'middle',
},
button: {
margin: 0,
padding: 0,
minWidth: 32,
},
deleteButton: {
minWidth: 32,
color: theme.palette.getContrastText(red[500]),
backgroundColor: red[500],
'&:hover': {
backgroundColor: red[700],
},
},
deviceLink: {
textDecoration: 'none',
'&,&:hover': {
color: '#000000',
},
},
},
deviceLink: {
textDecoration: "none",
"&,&:hover": {
color: "#000000"
}
}
});
class DevicesTableItem extends React.Component {
handleDeleteDevice = () => {
this.props.onDelete(this.props.device.id);
};
handleDeleteDevice = () => {
this.props.onDelete(this.props.device.id)
}
render() {
const { classes, device, onDelete } = this.props;
return (
<TableRow key={device.id}>
<TableCell component="th" scope="row">
<NavLink
to={'/devices/' + device.id}
className={classes.deviceLink}
key={device.id}>
{device.config.name}
</NavLink>
</TableCell>
<TableCell className={classes.tableCell}>
{device.config.ip_address}
</TableCell>
<TableCell className={classes.tableCell}>
{device.config.pixel_count}
</TableCell>
<TableCell className={classes.tableCell}>
{device.type}
</TableCell>
<TableCell className={classes.tableCell} numeric>
<Button variant="contained" size="small" className={classes.deleteButton} onClick={this.handleDeleteDevice} >
<DeleteIcon style={{ fontSize: 16 }} />
</Button>
</TableCell>
</TableRow>
);
}
render() {
const { classes, device } = this.props;
return (
<TableRow key={device.id}>
<TableCell component="th" scope="row">
<NavLink
to={'/devices/' + device.id}
className={classes.deviceLink}
key={device.id}
>
{device.config.name}
</NavLink>
</TableCell>
<TableCell className={classes.tableCell}>{device.config.ip_address}</TableCell>
<TableCell className={classes.tableCell}>{device.config.pixel_count}</TableCell>
<TableCell className={classes.tableCell}>{device.type}</TableCell>
<TableCell className={classes.tableCell} numeric>
<Button
variant="contained"
size="small"
className={classes.deleteButton}
onClick={this.handleDeleteDevice}
>
<DeleteIcon style={{ fontSize: 16 }} />
</Button>
</TableCell>
</TableRow>
);
}
}
DevicesTableItem.propTypes = {
classes: PropTypes.object.isRequired,
device: PropTypes.object.isRequired,
onDelete: PropTypes.func.isRequired
classes: PropTypes.object.isRequired,
device: PropTypes.object.isRequired,
onDelete: PropTypes.func.isRequired,
};
export default withStyles(styles)(DevicesTableItem);
export default withStyles(styles)(DevicesTableItem);

View File

@ -1,104 +1,97 @@
import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import withStyles from "@material-ui/core/styles/withStyles";
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import withStyles from '@material-ui/core/styles/withStyles';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import Typography from "@material-ui/core/Typography";
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import SchemaFormCollection from "../../components/SchemaForm/SchemaFormCollection.jsx";
import {
setDeviceEffect,
fetchDeviceEffects
} from "../../actions";
import SchemaFormCollection from '../../components/SchemaForm/SchemaFormCollection.jsx';
import { setDeviceEffect, fetchDeviceEffects } from '../../actions';
const styles = theme => ({
button: {
margin: theme.spacing.unit,
float: "right"
},
submitControls: {
margin: theme.spacing.unit,
display: "block",
width: "100%"
},
button: {
margin: theme.spacing.unit,
float: 'right',
},
submitControls: {
margin: theme.spacing.unit,
display: 'block',
width: '100%',
},
});
class EffectControl extends React.Component {
componentDidMount() {
this.props.dispatch(fetchDeviceEffects(this.props.device.id));
}
componentDidMount() {
this.props.dispatch(fetchDeviceEffects(this.props.device.id));
}
handleClearEffect = () => {
this.props.dispatch(setDeviceEffect(this.props.device.id, null, null));
};
handleClearEffect = () => {
this.props.dispatch(setDeviceEffect(this.props.device.id, null, null))
};
handleSetEffect = (type, config) => {
this.props.dispatch(setDeviceEffect(this.props.device.id, type, config));
};
handleSetEffect = (type, config) => {
this.props.dispatch(setDeviceEffect(this.props.device.id, type, config))
};
render() {
const { classes, schemas, effect } = this.props;
render() {
const { classes, schemas, effect } = this.props;
if (schemas.effects) {
var effectvalue = "";
if(effect !== undefined && effect !== null && effect.effect !== null)
effectvalue = effect.effect.type;
return (
<div>
<Typography variant="h5" color="inherit">
Effect Control
</Typography>
<SchemaFormCollection
schemaCollection={schemas.effects}
currentEffect={effect}
onSubmit={this.handleSetEffect}
>
<div className={classes.submitControls}>
<Button
className={classes.button}
type="submit"
variant="contained"
color="primary"
>
Set Effect
</Button>
<Button
className={classes.button}
onClick={this.handleClearEffect}
color="primary"
>
Clear Effect
</Button>
</div>
</SchemaFormCollection>
</div>
);
}
console.log('what the prosp for effect control', this.props);
return (<p>Loading</p>)
}
if (schemas.effects) {
// var effectValue = '';
// if (effect !== undefined && effect !== null && effect.effect !== null)
// effectValue = effect.effect.type;
return (
<div>
<Typography variant="h5" color="inherit">
Effect Control
</Typography>
<SchemaFormCollection
schemaCollection={schemas.effects}
currentEffect={effect}
onSubmit={this.handleSetEffect}
>
<div className={classes.submitControls}>
<Button
className={classes.button}
type="submit"
variant="contained"
color="primary"
>
Set Effect
</Button>
<Button
className={classes.button}
onClick={this.handleClearEffect}
color="primary"
>
Clear Effect
</Button>
</div>
</SchemaFormCollection>
</div>
);
}
return <p>Loading</p>;
}
}
EffectControl.propTypes = {
classes: PropTypes.object.isRequired,
schemas: PropTypes.object.isRequired,
device: PropTypes.object.isRequired,
effect: PropTypes.object.isRequired
classes: PropTypes.object.isRequired,
schemas: PropTypes.object.isRequired,
device: PropTypes.object.isRequired,
effect: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
const { schemas } = state;
const { schemas } = state;
return {
schemas
};
return {
schemas,
};
}
export default connect(mapStateToProps)(withStyles(styles)(EffectControl));

View File

@ -1,5 +1,4 @@
import React from "react";
import classNames from "classnames";
import PropTypes from "prop-types";
import { connect } from "react-redux";
@ -8,7 +7,6 @@ import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import IconButton from "@material-ui/core/IconButton";
import Hidden from "@material-ui/core/Hidden";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import Menu from "@material-ui/icons/Menu";
@ -29,7 +27,7 @@ class Header extends React.Component {
const path = this.props.location.pathname
if (path.startsWith("/devices/")) {
const deviceId = path.replace("/devices/", "");
const deviceName = this.props.devicesById[deviceId] != undefined ?
const deviceName = this.props.devicesById[deviceId] !== undefined ?
this.props.devicesById[deviceId].config.name : ""
name = "Devices / " + deviceName
}
@ -41,7 +39,7 @@ class Header extends React.Component {
}
render() {
const { classes, color } = this.props;
const { classes } = this.props;
return (
<AppBar className={classes.appBar}>

View File

@ -1,6 +1,6 @@
import {
drawerWidth
} from "../../assets/jss/style";
} from "assets/jss/style";
const headerStyle = theme => ({

View File

@ -1,170 +1,176 @@
import React from "react";
import PropTypes from "prop-types";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import withStyles from "@material-ui/core/styles/withStyles";
import React from 'react';
import PropTypes from 'prop-types';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import withStyles from '@material-ui/core/styles/withStyles';
import { Line } from 'react-chartjs-2';
import Sockette from 'sockette';
const styles = theme => ({
content: {
minWidth: 120,
maxWidth: '100%'
}
content: {
minWidth: 120,
maxWidth: '100%',
},
});
class PixelColorGraph extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props)
this.websocketPacketId = 1;
this.deviceUpdateSubscription = null;
this.websocketPacketId = 1
this.deviceUpdateSubscription = null
this.state = {
chartData: {
labels: [],
datasets: [
{
label: 'Melbank',
lineTension: 0.1,
backgroundColor: 'rgba(0,0,0,0.1)',
borderColor: 'rgba(0,0,0,1)',
pointRadius: 0,
data: [],
},
],
},
chartOptions: {
responsive: true,
maintainAspectRatio: false,
tooltips: { enabled: false },
hover: { mode: null },
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0,
scales: {
xAxes: [
{
gridLines: {
display: false,
},
ticks: {
maxTicksLimit: 7,
callback: function(value, index, values) {
return value + ' Hz';
},
},
},
],
yAxes: [
{
ticks: {
min: 0,
max: 2.0,
stepSize: 0.5,
},
gridLines: {
color: 'rgba(0, 0, 0, .125)',
},
},
],
},
legend: {
display: false,
},
},
};
}
this.state = {
chartData: {
labels: [],
datasets: [
{
label: "Melbank",
lineTension: 0.1,
backgroundColor: "rgba(0,0,0,0.1)",
borderColor: "rgba(0,0,0,1)",
pointRadius: 0,
data: [],
}],
},
chartOptions: {
responsive: true,
maintainAspectRatio: false,
tooltips: {enabled: false},
hover: {mode: null},
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0,
scales: {
xAxes: [{
gridLines: {
display: false
},
ticks: {
maxTicksLimit: 7,
callback: function(value, index, values) {
return value + ' Hz';
}
}
}],
yAxes: [{
ticks: {
min: 0,
max: 2.0,
stepSize: 0.5
},
gridLines: {
color: "rgba(0, 0, 0, .125)",
}
}],
},
legend: {
display: false
handleMessage = e => {
var chartData = this.state.chartData;
var messageData = JSON.parse(e.data);
chartData.labels = messageData.frequencies;
chartData.datasets[0].data = messageData.melbank;
// Adjust the axes based on the max
var melbankMax = Math.max.apply(Math, messageData.melbank);
var chartOptions = this.state.chartOptions;
chartOptions.scales.yAxes[0].ticks.min = 0;
chartOptions.scales.yAxes[0].ticks.max = Math.max(
chartOptions.scales.yAxes[0].ticks.max,
melbankMax
);
chartOptions.scales.yAxes[0].ticks.stepSize = chartOptions.scales.yAxes[0].ticks.max / 4;
this.setState({ chartData: chartData, chartOptions: chartOptions });
};
handleOpen = e => {
this.enablePixelVisualization();
};
handleClose = e => {};
enablePixelVisualization = () => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'subscribe_event',
event_type: 'graph_update',
event_filter: { graph_id: this.props.graphId },
});
this.deviceUpdateSubscription = this.websocketPacketId;
this.websocketPacketId++;
};
disablePixelVisualization = () => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'unsubscribe_event',
subscription_id: this.deviceUpdateSubscription,
});
this.deviceUpdateSubscription = null;
this.websocketPacketId++;
};
connectWebsocket = () => {
const websocketUrl = 'ws://' + window.location.host + '/api/websocket';
const ws = new Sockette(websocketUrl, {
timeout: 5e3,
maxAttempts: 10,
onopen: this.handleOpen,
onmessage: this.handleMessage,
onclose: this.handleClose,
onerror: e => console.log('WebSocket Error:', e),
});
this.setState({ ws: ws });
};
disconnectWebsocket = () => {
if (this.state.ws != undefined) {
this.state.ws.close(1000);
this.setState({ ws: undefined });
}
}
};
componentDidMount() {
this.connectWebsocket();
}
}
handleMessage = e => {
var chartData = this.state.chartData;
var messageData = JSON.parse(e.data);
chartData.labels = messageData.frequencies
chartData.datasets[0].data = messageData.melbank
// Adjust the axes based on the max
var melbankMax = Math.max.apply(Math, messageData.melbank);
var chartOptions = this.state.chartOptions;
chartOptions.scales.yAxes[0].ticks.min = 0
chartOptions.scales.yAxes[0].ticks.max = Math.max(chartOptions.scales.yAxes[0].ticks.max, melbankMax)
chartOptions.scales.yAxes[0].ticks.stepSize = chartOptions.scales.yAxes[0].ticks.max / 4
this.setState(...this.state, {chartData: chartData, chartOptions: chartOptions})
}
handleOpen = e => {
this.enablePixelVisualization();
}
handleClose = e => {
}
enablePixelVisualization = () => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'subscribe_event',
event_type: 'graph_update',
event_filter: { 'graph_id': this.props.graphId }
})
this.deviceUpdateSubscription = this.websocketPacketId;
this.websocketPacketId++;
}
disablePixelVisualization = () => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'unsubscribe_event',
subscription_id: this.deviceUpdateSubscription
})
this.deviceUpdateSubscription = null;
this.websocketPacketId++;
}
connectWebsocket = () => {
const websocketUrl = 'ws://' + window.location.host + '/api/websocket';
const ws = new Sockette(websocketUrl, {
timeout: 5e3,
maxAttempts: 10,
onopen: this.handleOpen,
onmessage: this.handleMessage,
onclose: this.handleClose,
onerror: e => console.log('WebSocket Error:', e)
});
this.setState(...this.state, {ws: ws});
}
disconnectWebsocket = () => {
if (this.state.ws != undefined) {
this.state.ws.close(1000);
this.setState(...this.state, {ws: undefined});
componentWillUnmount() {
this.disconnectWebsocket();
}
}
componentDidMount() {
this.connectWebsocket()
}
render() {
const { classes } = this.props;
componentWillUnmount() {
this.disconnectWebsocket();
}
render() {
const { classes } = this.props;
return (
<Card>
<CardContent className={classes.content}>
<Line data={this.state.chartData} options={this.state.chartOptions}/>
</CardContent>
</Card>
);
}
return (
<Card>
<CardContent className={classes.content}>
<Line data={this.state.chartData} options={this.state.chartOptions} />
</CardContent>
</Card>
);
}
}
PixelColorGraph.propTypes = {
classes: PropTypes.object.isRequired,
graphId: PropTypes.string.isRequired
classes: PropTypes.object.isRequired,
graphId: PropTypes.string.isRequired,
};
export default withStyles(styles)(PixelColorGraph);
export default withStyles(styles)(PixelColorGraph);

View File

@ -1,203 +1,199 @@
import React from "react";
import PropTypes from "prop-types";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import withStyles from "@material-ui/core/styles/withStyles";
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import { Line } from 'react-chartjs-2';
import Sockette from 'sockette';
const styles = theme => ({
content: {
minWidth: 120,
maxWidth: '100%'
}
content: {
minWidth: 120,
maxWidth: '100%',
},
});
class PixelColorGraph extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props)
this.websocketActive = false;
this.websocketPacketId = 1;
this.deviceUpdateSubscription = null;
this.state = this.getChartOptionsForDevice(props.device);
}
this.websocketActive = false;
this.websocketPacketId = 1
this.deviceUpdateSubscription = null
this.state = this.getChartOptionsForDevice(props.device)
}
getChartOptionsForDevice(device)
{
return {
chartData: {
labels: Array.apply(null, {length: device.config.pixel_count}).map(
Function.call, Number),
datasets: [
{
label: "Red",
lineTension: 0.1,
backgroundColor: "rgba(255,0,0,0.1)",
borderColor: "rgba(255,0,0,1)",
pointRadius: 0,
data: new Array(device.config.pixel_count).fill(0),
},
{
label: "Green",
lineTension: 0.1,
backgroundColor: "rgba(0,255,0,0.1)",
borderColor: "rgba(0,255,0,1)",
pointRadius: 0,
data: new Array(device.config.pixel_count).fill(0),
},
{
label: "Blue",
lineTension: 0.1,
backgroundColor: "rgba(0,0,255,0.1)",
borderColor: "rgba(0,0,255,1)",
pointRadius: 0,
data: new Array(device.config.pixel_count).fill(0),
}],
},
chartOptions: {
responsive: true,
maintainAspectRatio: false,
tooltips: {enabled: false},
hover: {mode: null},
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0,
scales: {
xAxes: [{
gridLines: {
display: false
getChartOptionsForDevice(device) {
return {
chartData: {
labels: Array.apply(null, { length: device.config.pixel_count }).map(
Function.call,
Number
),
datasets: [
{
label: 'Red',
lineTension: 0.1,
backgroundColor: 'rgba(255,0,0,0.1)',
borderColor: 'rgba(255,0,0,1)',
pointRadius: 0,
data: new Array(device.config.pixel_count).fill(0),
},
{
label: 'Green',
lineTension: 0.1,
backgroundColor: 'rgba(0,255,0,0.1)',
borderColor: 'rgba(0,255,0,1)',
pointRadius: 0,
data: new Array(device.config.pixel_count).fill(0),
},
{
label: 'Blue',
lineTension: 0.1,
backgroundColor: 'rgba(0,0,255,0.1)',
borderColor: 'rgba(0,0,255,1)',
pointRadius: 0,
data: new Array(device.config.pixel_count).fill(0),
},
],
},
ticks: {
max: device.config.pixel_count,
min: 0,
maxTicksLimit: 7
}
}],
yAxes: [{
ticks: {
display: false,
min: 0,
max: 256,
stepSize: 64
chartOptions: {
responsive: true,
maintainAspectRatio: false,
tooltips: { enabled: false },
hover: { mode: null },
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0,
scales: {
xAxes: [
{
gridLines: {
display: false,
},
ticks: {
max: device.config.pixel_count,
min: 0,
maxTicksLimit: 7,
},
},
],
yAxes: [
{
ticks: {
display: false,
min: 0,
max: 256,
stepSize: 64,
},
gridLines: {
display: false,
color: 'rgba(0, 0, 0, .125)',
},
},
],
},
legend: {
display: false,
},
},
gridLines: {
display: false,
color: "rgba(0, 0, 0, .125)",
}
}],
},
legend: {
display: false
};
}
handleMessage = e => {
var messageData = JSON.parse(e.data);
// Ensure this message is for the current device. This can happen
// during transistions between devices where the component stays
// loaded
if (messageData.device_id != this.props.device.id) {
return;
}
}
}
}
handleMessage = e => {
var messageData = JSON.parse(e.data);
var chartData = this.state.chartData;
chartData.datasets[0].data = messageData.pixels[0];
chartData.datasets[1].data = messageData.pixels[1];
chartData.datasets[2].data = messageData.pixels[2];
this.setState({ chartData });
};
// Ensure this message is for the current device. This can happen
// during transistions between devices where the component stays
// loaded
if (messageData.device_id != this.props.device.id) {
return;
handleOpen = e => {
this.enablePixelVisualization(this.props.device);
this.websocketActive = true;
};
handleClose = e => {
this.websocketActive = false;
};
enablePixelVisualization = device => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'subscribe_event',
event_type: 'device_update',
event_filter: { device_id: device.id },
});
this.deviceUpdateSubscription = this.websocketPacketId;
this.websocketPacketId++;
};
disablePixelVisualization = () => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'unsubscribe_event',
subscription_id: this.deviceUpdateSubscription,
});
this.deviceUpdateSubscription = null;
this.websocketPacketId++;
};
connectWebsocket = () => {
const websocketUrl = 'ws://' + window.location.host + '/api/websocket';
const ws = new Sockette(websocketUrl, {
timeout: 5e3,
maxAttempts: 10,
onopen: this.handleOpen,
onmessage: this.handleMessage,
onclose: this.handleClose,
onerror: e => console.log('WebSocket Error:', e),
});
this.setState({ ws });
};
disconnectWebsocket = () => {
if (this.state.ws != undefined && this.websocketActive) {
this.state.ws.close(1000);
this.setState({ ws: undefined });
}
};
componentDidMount() {
this.connectWebsocket();
}
var chartData = this.state.chartData
chartData.datasets[0].data = messageData.pixels[0]
chartData.datasets[1].data = messageData.pixels[1]
chartData.datasets[2].data = messageData.pixels[2]
this.setState(...this.state, {chartData: chartData})
}
handleOpen = e => {
this.enablePixelVisualization(this.props.device);
this.websocketActive = true
}
handleClose = e => {
this.websocketActive = false
}
enablePixelVisualization = (device) => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'subscribe_event',
event_type: 'device_update',
event_filter: { 'device_id': device.id }
})
this.deviceUpdateSubscription = this.websocketPacketId;
this.websocketPacketId++;
}
disablePixelVisualization = () => {
this.state.ws.json({
id: this.websocketPacketId,
type: 'unsubscribe_event',
subscription_id: this.deviceUpdateSubscription
})
this.deviceUpdateSubscription = null;
this.websocketPacketId++;
}
connectWebsocket = () => {
const websocketUrl = 'ws://' + window.location.host + '/api/websocket';
const ws = new Sockette(websocketUrl, {
timeout: 5e3,
maxAttempts: 10,
onopen: this.handleOpen,
onmessage: this.handleMessage,
onclose: this.handleClose,
onerror: e => console.log('WebSocket Error:', e)
});
this.setState(...this.state, {ws: ws});
}
disconnectWebsocket = () => {
if (this.state.ws != undefined &&
this.websocketActive) {
this.state.ws.close(1000);
this.setState(...this.state, {ws: undefined});
componentWillUnmount() {
this.disconnectWebsocket();
}
}
componentDidMount() {
this.connectWebsocket()
}
componentWillUnmount() {
this.disconnectWebsocket();
}
componentWillReceiveProps(nextProps) {
if (this.websocketActive) {
this.disablePixelVisualization()
this.enablePixelVisualization(nextProps.device)
this.setState(...this.state,
this.getChartOptionsForDevice(nextProps.device))
componentWillReceiveProps(nextProps) {
if (this.websocketActive) {
this.disablePixelVisualization();
this.enablePixelVisualization(nextProps.device);
this.setState({ ...this.getChartOptionsForDevice(nextProps.device) });
}
}
}
render() {
const { classes, device } = this.props;
return (
<Line data={this.state.chartData} options={this.state.chartOptions}/>
);
}
render() {
return <Line data={this.state.chartData} options={this.state.chartOptions} />;
}
}
PixelColorGraph.propTypes = {
classes: PropTypes.object.isRequired,
device: PropTypes.object.isRequired
classes: PropTypes.object.isRequired,
device: PropTypes.object.isRequired,
};
export default withStyles(styles)(PixelColorGraph);
export default withStyles(styles)(PixelColorGraph);

View File

@ -1,5 +1,4 @@
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import { connect } from 'react-redux';
@ -7,7 +6,6 @@ import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContentText from '@material-ui/core/DialogContentText';
import SchemaFormCollection from 'components/SchemaForm/SchemaFormCollection.jsx';
@ -20,10 +18,6 @@ const styles = theme => ({
});
class PresetsConfigDialog extends React.Component {
constructor(props) {
super(props);
}
handleClose = () => {
this.props.onClose();
};

View File

@ -1,215 +1,229 @@
import React from "react";
import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles";
import { MuiThemeProvider } from "@material-ui/core/styles";
import React from 'react';
import PropTypes from 'prop-types';
import withStyles from '@material-ui/core/styles/withStyles';
import Select from "@material-ui/core/Select";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import Input from '@material-ui/core/Input';
import Select from '@material-ui/core/Select';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Button from "@material-ui/core/Button";
import Collapse from "@material-ui/core/Collapse";
import { defaultTheme } from "layouts/Default/Default"
//import SchemaForm from "components/SchemaForm/SchemaForm.;
import Button from '@material-ui/core/Button';
import Collapse from '@material-ui/core/Collapse';
import { selectOrSet } from "components/SchemaForm/Utils";
import { selectOrSet } from 'components/SchemaForm/Utils';
var { SchemaForm } = require('react-schema-form');
const styles = theme => ({
form: {
display: "flex",
flexWrap: "wrap"
},
flexWrap: {
display: "flex",
flexWrap: "wrap"
},
control: {
margin: theme.spacing.unit,
width: '100%'
},
schemaForm: {
marginLeft: 2 * theme.spacing.unit,
marginRight: 2 * theme.spacing.unit,
display: "flex",
flexWrap: "wrap",
width: "100%"
},
additionalWrapper: {
display: "inline-grid"
},
additionalButton: {
display: "block",
width: "100%",
float: "right"
}
form: {
display: 'flex',
flexWrap: 'wrap',
},
flexWrap: {
display: 'flex',
flexWrap: 'wrap',
},
control: {
margin: theme.spacing.unit,
width: '100%',
},
schemaForm: {
marginLeft: 2 * theme.spacing.unit,
marginRight: 2 * theme.spacing.unit,
display: 'flex',
flexWrap: 'wrap',
width: '100%',
},
additionalWrapper: {
display: 'inline-grid',
},
additionalButton: {
display: 'block',
width: '100%',
float: 'right',
},
});
class SchemaFormCollection extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
collectionKey: "",
interRender : false,
showAdditional: false,
model: {},
form: [
"*",
{
type: "submit",
title: "Save"
}
],
action: [[
{
"category" : "user",
"name" : "addAddress",
"readOnly": false,
"title" : "New"
}
]]
this.state = {
collectionKey: '',
interRender: false,
showAdditional: false,
model: {},
form: [
'*',
{
type: 'submit',
title: 'Save',
},
],
action: [
[
{
category: 'user',
name: 'addAddress',
readOnly: false,
title: 'New',
},
],
],
};
}
showAdditional = () => {
this.setState({
showAdditional: !this.state.showAdditional,
});
};
}
componentDidMount() {
}
showAdditional = () => {
this.setState(...this.state, {
showAdditional: !this.state.showAdditional
});
};
handleChangeSelectedCollection = event => {
this.setState({ collectionKey: event.target.value, interRender: true });
if (this.props.onChange) {
this.props.onChange(event.target.value, {});
}
};
onModelChange = (key, val) => {
selectOrSet(key, this.state.model, val);
};
handleChangeSelectedCollection = event => {
this.state.interRender = true;
this.setState({ collectionKey: event.target.value });
if (this.props.onChange) {
this.props.onChange(event.target.value, {})
handleSubmit = event => {
event.preventDefault();
if (this.props.onSubmit) {
this.props.onSubmit(this.state.collectionKey, this.state.model);
}
};
render() {
const {
children,
classes,
onChange,
onSubmit,
schemaCollection,
currentEffect,
useAdditionalProperties,
...otherProps
} = this.props;
// if (
// currentEffect !== undefined &&
// currentEffect !== null &&
// currentEffect.effect !== null &&
// this.state.interRender === false
// ) {
// this.setState({
// collectionKey: currentEffect.effect.type || '',
// model: currentEffect.effect.config || {},
// interRender: false,
// });
// }
let currentSchema = {
type: 'object',
title: 'Effect Configuration',
properties: {},
};
if (this.state.collectionKey !== '') {
currentSchema = {
...currentSchema,
...schemaCollection[this.state.collectionKey].schema,
};
}
let customSelect = (
<FormControl className={classes.control}>
<InputLabel>Type</InputLabel>
<Select
value={this.state.collectionKey}
onChange={this.handleChangeSelectedCollection}
>
<MenuItem value="" select="selected">
<em>None</em>
</MenuItem>
{Object.keys(schemaCollection).map(collectionKey => {
return (
<MenuItem key={collectionKey} value={collectionKey}>
{collectionKey}
</MenuItem>
);
})}
</Select>
</FormControl>
);
var additionUi = null;
var form = ['*'];
const requiredKeys = currentSchema['required'];
const optionalKeys = Object.keys(currentSchema['properties']).filter(
key => requiredKeys && requiredKeys.indexOf(key) === -1
);
if (useAdditionalProperties && optionalKeys.length) {
form = requiredKeys;
additionUi = (
<div className={classes.additionalWrapper}>
<Button
size="small"
className={classes.additionalButton}
onClick={this.showAdditional}
>
Additional Configuration
</Button>
<Collapse in={this.state.showAdditional}>
<div className={classes.flexWrap}>
<SchemaForm
className={classes.schemaForm}
schema={currentSchema}
form={optionalKeys}
model={this.state.model}
onModelChange={this.onModelChange}
{...otherProps}
/>
</div>
</Collapse>
</div>
);
}
return (
<form onSubmit={this.handleSubmit} className={classes.form}>
{customSelect}
<SchemaForm
className={classes.schemaForm}
schema={currentSchema}
form={form}
model={this.state.model}
onModelChange={this.onModelChange}
{...otherProps}
/>
{additionUi}
{children ? (
children
) : (
<Button type="submit" className={classes.button}>
Submit
</Button>
)}
</form>
);
}
};
onModelChange = (key, val) => {
selectOrSet(key, this.state.model, val);
}
handleSubmit = event => {
event.preventDefault();
if (this.props.onSubmit) {
this.props.onSubmit(this.state.collectionKey, this.state.model)
}
}
render() {
const { children, classes, onChange, onSubmit, schemaCollection, currentEffect, useAdditionalProperties, ...otherProps } = this.props;
if(currentEffect !== undefined && currentEffect !== null && currentEffect.effect !== null && this.state.interRender == false)
{
if(currentEffect.effect.type === undefined)
this.state.collectionKey = "";
else
this.state.collectionKey = currentEffect.effect.type;
if(currentEffect.effect.config === undefined)
this.state.model = {};
else
this.state.model = currentEffect.effect.config;
}
this.state.interRender = false;
var currentSchema = {"type": "object", "title": "Effect Configuration", properties: {}}
if (this.state.collectionKey !== "" ) {
currentSchema = {...currentSchema, ...schemaCollection[this.state.collectionKey].schema};
}
let customSelect = (
<FormControl className={classes.control}>
<InputLabel>Type</InputLabel>
<Select
value={this.state.collectionKey}
onChange={this.handleChangeSelectedCollection}
>
<MenuItem value="" select='selected'>
<em>None</em>
</MenuItem>
{Object.keys(schemaCollection).map(collectionKey => {
return (
<MenuItem key={collectionKey} value={collectionKey}>
{collectionKey}
</MenuItem>
);
})}
</Select>
</FormControl>
);
var additionUi = null
var form = ["*"]
const requiredKeys = currentSchema['required'];
const optionalKeys = Object.keys(currentSchema['properties']).filter(
key => requiredKeys && requiredKeys.indexOf(key) === -1);
if (useAdditionalProperties && optionalKeys.length)
{
form = requiredKeys;
additionUi = (
<div className={classes.additionalWrapper}>
<Button
size="small"
className={classes.additionalButton}
onClick={this.showAdditional}
>
Additional Configuration
</Button>
<Collapse in={this.state.showAdditional}>
<div className={classes.flexWrap} >
<SchemaForm
className={classes.schemaForm}
schema={currentSchema}
form={optionalKeys}
model={this.state.model}
onModelChange={this.onModelChange}
{...otherProps} />
</div>
</Collapse>
</div>
);
}
return (
<form onSubmit={this.handleSubmit} className={classes.form}>
{customSelect}
<SchemaForm
className={classes.schemaForm}
schema={currentSchema}
form={form}
model={this.state.model}
onModelChange={this.onModelChange}
{...otherProps} />
{additionUi}
{children ? (children) : (
<Button type="submit" className={classes.button}>
Submit
</Button>
)}
</form>
);
}
}
SchemaFormCollection.propTypes = {
onChange: PropTypes.func,
classes: PropTypes.object.isRequired,
schemaCollection: PropTypes.object.isRequired
onChange: PropTypes.func.isRequired,
classes: PropTypes.object,
schemaCollection: PropTypes.object,
};
SchemaFormCollection.defaultProps = {
classes: '',
schemaCollection: {},
};
export default withStyles(styles)(SchemaFormCollection);

View File

@ -1,210 +1,204 @@
import React from "react";
import classNames from "classnames";
import PropTypes from "prop-types";
import { connect } from 'react-redux'
import { NavLink } from "react-router-dom";
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';
import withStyles from "@material-ui/core/styles/withStyles";
import Drawer from "@material-ui/core/Drawer";
import Hidden from "@material-ui/core/Hidden";
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 withStyles from '@material-ui/core/styles/withStyles';
import Drawer from '@material-ui/core/Drawer';
import Hidden from '@material-ui/core/Hidden';
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 sidebarStyle from "./style.jsx";
import viewRoutes from "routes/views.jsx";
import sidebarStyle from './style.jsx';
import viewRoutes from 'routes/views.jsx';
//import logoAsset from "assets/img/logo.png";
import logoAsset from "assets/img/icon/small_white_alpha.png";
import logoAsset from 'assets/img/icon/small_white_alpha.png';
import { getSystemConfig } from "actions";
import { getSystemConfig } from 'proxies/config';
class Sidebar extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
devMode: false
this.state = {
devMode: false,
};
}
getSystemConfig().then(json => {
var devMode = false;
if (json.config.dev_mode)
{
devMode = true;
}
this.setState({devMode: devMode});
});
}
isViewActive(viewName) {
return this.props.location.pathname == viewName;//.indexOf(viewName) > -1 ? true : false;
}
componentDidMount() {
getSystemConfig().then(config => {
console.log('whats this config', config);
render() {
const { classes, color, devicesById, effectLinks } = this.props;
this.setState({ devMode: config.dev_mode });
});
}
var deviceLinks = Object.keys(devicesById).map(deviceId => {
var listItemClass = classes.itemLink
if (this.isViewActive("/devices/" + deviceId))
{
listItemClass = listItemClass + " " + classes.activeView
}
return (
<NavLink
to={'/devices/' + devicesById[deviceId].id}
className={classes.item}
key={devicesById[deviceId].id}
activeClassName="active"
key={deviceId}>
<ListItem button className={listItemClass}>
<ListItemText
primary={devicesById[deviceId].config.name}
className={classes.devicesItemText}
disableTypography={true}/>
</ListItem>
</NavLink>
);
});
isViewActive(viewName) {
return this.props.location.pathname === viewName; //.indexOf(viewName) > -1 ? true : false;
}
var links = (
<List className={classes.list}>
{
viewRoutes.map((prop, key) => {
if (prop.redirect || !prop.sidebarName) {
return null;
render() {
const { classes, devicesById, effectLinks } = this.props;
var deviceLinks = Object.keys(devicesById).map(deviceId => {
var listItemClass = classes.itemLink;
if (this.isViewActive('/devices/' + deviceId)) {
listItemClass = listItemClass + ' ' + classes.activeView;
}
if (prop.sidebarName === "Developer" && !this.state.devMode) {
return null;
}
var listItemClass = classes.itemLink
if (this.isViewActive(prop.path) && prop.sidebarName != "Devices") {
listItemClass = listItemClass + " " + classes.activeView
}
if (this.isViewActive(prop.path) && prop.sidebarName != "EffectPresets") {
listItemClass = listItemClass + " " + classes.activeView
}
if (prop.sidebarName === "Devices")
{
return (
<ListItem button className={listItemClass}>
<ListItemIcon className={classes.itemIcon}>
<prop.icon />
</ListItemIcon>
<ListItemText
primary={prop.sidebarName}
className={classes.itemText}
disableTypography={true}/>
<List className={classes.list}>
{deviceLinks}
</List>
</ListItem>
);
}
if (prop.sidebarName === "EffectPresets")
{
return (
<ListItem button className={listItemClass}>
<ListItemIcon className={classes.itemIcon}>
<prop.icon />
</ListItemIcon>
<ListItemText
primary={prop.sidebarName}
className={classes.itemText}
disableTypography={true}/>
<List className={classes.list}>
{effectLinks}
</List>
</ListItem>
);
}
return (
<NavLink
to={prop.path}
className={classes.item}
activeClassName="active"
key={key}>
<ListItem button className={listItemClass}>
<ListItemIcon className={classes.itemIcon}>
<prop.icon />
</ListItemIcon>
<ListItemText
primary={prop.sidebarName}
className={classes.itemText}
disableTypography={true}/>
</ListItem>
</NavLink>
<NavLink
to={'/devices/' + devicesById[deviceId].id}
className={classes.item}
key={devicesById[deviceId].id}
activeClassName="active"
>
<ListItem button className={listItemClass}>
<ListItemText
primary={devicesById[deviceId].config.name}
className={classes.devicesItemText}
disableTypography={true}
/>
</ListItem>
</NavLink>
);
})
}
</List>
);
});
var logo = (
<div className={classes.logo}>
<a href="#" className={classes.logoLink}>
<div className={classes.logoImage}>
<img src={logoAsset} alt="logo" className={classes.img} />
</div>
LedFx
</a>
</div>
);
var links = (
<List className={classes.list}>
{viewRoutes.map((prop, key) => {
if (prop.redirect || !prop.sidebarName) {
return null;
}
return (
<div>
<Hidden mdUp>
<Drawer
variant="temporary"
anchor="right"
open={this.props.open}
classes={{
paper: classes.drawerPaper
}}
onClose={this.props.handleDrawerToggle}
ModalProps={{
keepMounted: true
}}>
if (prop.sidebarName === 'Developer' && !this.state.devMode) {
return null;
}
{logo}
<div className={classes.sidebarWrapper}>{links}</div>
<div className={classes.background}/>
</Drawer>
</Hidden>
<Hidden smDown implementation="css">
<Drawer
open
variant="permanent"
classes={{
paper: classes.drawerPaper
}}>
var listItemClass = classes.itemLink;
if (this.isViewActive(prop.path) && prop.sidebarName !== 'Devices') {
listItemClass = listItemClass + ' ' + classes.activeView;
}
if (this.isViewActive(prop.path) && prop.sidebarName !== 'EffectPresets') {
listItemClass = listItemClass + ' ' + classes.activeView;
}
{logo}
<div className={classes.sidebarWrapper}>{links}</div>
<div className={classes.background}/>
</Drawer>
</Hidden>
</div>
);
}
if (prop.sidebarName === 'Devices') {
return (
<ListItem button className={listItemClass}>
<ListItemIcon className={classes.itemIcon}>
<prop.icon />
</ListItemIcon>
<ListItemText
primary={prop.sidebarName}
className={classes.itemText}
disableTypography={true}
/>
<List className={classes.list}>{deviceLinks}</List>
</ListItem>
);
}
if (prop.sidebarName === 'EffectPresets') {
return (
<ListItem button className={listItemClass}>
<ListItemIcon className={classes.itemIcon}>
<prop.icon />
</ListItemIcon>
<ListItemText
primary={prop.sidebarName}
className={classes.itemText}
disableTypography={true}
/>
<List className={classes.list}>{effectLinks}</List>
</ListItem>
);
}
return (
<NavLink
to={prop.path}
className={classes.item}
activeClassName="active"
key={key}
>
<ListItem button className={listItemClass}>
<ListItemIcon className={classes.itemIcon}>
<prop.icon />
</ListItemIcon>
<ListItemText
primary={prop.sidebarName}
className={classes.itemText}
disableTypography={true}
/>
</ListItem>
</NavLink>
);
})}
</List>
);
var logo = (
<div className={classes.logo}>
<a href="/#" className={classes.logoLink}>
<div className={classes.logoImage}>
<img src={logoAsset} alt="logo" className={classes.img} />
</div>
LedFx
</a>
</div>
);
return (
<div>
<Hidden mdUp>
<Drawer
variant="temporary"
anchor="right"
open={this.props.open}
classes={{
paper: classes.drawerPaper,
}}
onClose={this.props.handleDrawerToggle}
ModalProps={{
keepMounted: true,
}}
>
{logo}
<div className={classes.sidebarWrapper}>{links}</div>
<div className={classes.background} />
</Drawer>
</Hidden>
<Hidden smDown implementation="css">
<Drawer
open
variant="permanent"
classes={{
paper: classes.drawerPaper,
}}
>
{logo}
<div className={classes.sidebarWrapper}>{links}</div>
<div className={classes.background} />
</Drawer>
</Hidden>
</div>
);
}
}
Sidebar.propTypes = {
classes: PropTypes.object.isRequired,
devicesById: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
devicesById: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
const { devicesById } = state
const { devicesById } = state;
return {
devicesById
}
return {
devicesById,
};
}
export default connect(mapStateToProps)(withStyles(sidebarStyle)(Sidebar));
export default connect(mapStateToProps)(withStyles(sidebarStyle)(Sidebar));

View File

@ -1,122 +1,115 @@
import React from "react";
import { connect } from "react-redux";
import { fetchDeviceList, fetchSchemasIfNeeded } from "../../actions";
import PropTypes from "prop-types";
import { Switch, Route, Redirect } from "react-router-dom";
import { MuiThemeProvider, createMuiTheme } from "@material-ui/core/styles";
import cyan from "@material-ui/core/colors/cyan";
import green from "@material-ui/core/colors/green";
import CssBaseline from "@material-ui/core/CssBaseline";
import withStyles from "@material-ui/core/styles/withStyles";
import React from 'react';
import { connect } from 'react-redux';
import { fetchDeviceList, fetchSchemasIfNeeded } from '../../actions';
import PropTypes from 'prop-types';
import { Switch, Route, Redirect } from 'react-router-dom';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import cyan from '@material-ui/core/colors/cyan';
import green from '@material-ui/core/colors/green';
import CssBaseline from '@material-ui/core/CssBaseline';
import withStyles from '@material-ui/core/styles/withStyles';
import Header from "../../components/Header/Header";
import Sidebar from "../../components/Sidebar/Sidebar";
import viewRoutes from "../../routes/views";
import dashboardStyle from "./style";
import logo from "../../assets/img/icon/small_white_alpha.png";
import Header from '../../components/Header/Header';
import Sidebar from '../../components/Sidebar/Sidebar';
import viewRoutes from '../../routes/views';
import dashboardStyle from './style';
const defaultTheme = createMuiTheme({
palette: {
primary: cyan,
secondary: green,
},
overrides: {
MuiFormControl: {
root: {
margin: 8,
minWidth: 225,
flex: "1 0 30%",
},
palette: {
primary: cyan,
secondary: green,
},
overrides: {
MuiFormControl: {
root: {
margin: 8,
minWidth: 225,
flex: '1 0 30%',
},
},
},
},
});
class DefaultLayout extends React.Component {
constructor(props) {
super(props);
this.state = {
mobileOpen: false,
theme: defaultTheme,
};
}
componentDidUpdate(e) {
if (e.history.location.pathname !== e.location.pathname) {
this.refs.root.scrollTop = 0;
if (this.state.mobileOpen) {
var newState = Object.assign({}, this.state, { mobileOpen: false });
this.setState(newState);
}
constructor(props) {
super(props);
this.state = {
mobileOpen: false,
theme: defaultTheme,
};
}
}
componentDidMount() {
this.props.dispatch(fetchDeviceList());
this.props.dispatch(fetchSchemasIfNeeded());
}
componentDidUpdate(e) {
if (e.history.location.pathname !== e.location.pathname) {
this.refs.root.scrollTop = 0;
if (this.state.mobileOpen) {
this.setState({ mobileOpen: false });
}
}
}
render() {
const { classes, rest } = this.props;
componentDidMount() {
this.props.dispatch(fetchDeviceList());
this.props.dispatch(fetchSchemasIfNeeded());
}
var handleDrawerToggle = () => {
var newState = Object.assign({}, this.state, {
mobileOpen: !this.state.mobileOpen,
});
this.setState(newState);
};
render() {
const { classes, rest } = this.props;
return (
<div className={classes.root} ref="root">
<CssBaseline />
<MuiThemeProvider theme={this.state.theme}>
<Header
handleDrawerToggle={handleDrawerToggle}
location={this.props.location}
/>
<Sidebar
handleDrawerToggle={handleDrawerToggle}
open={this.state.mobileOpen}
location={this.props.location}
/>
var handleDrawerToggle = () => {
this.setState(prevState => ({ mobileOpen: !prevState.mobileOpen }));
};
<div className={classes.content}>
<div className={classes.toolbar} />
<Switch>
{viewRoutes.map((prop, key) => {
if (prop.redirect) {
return <Redirect from={prop.path} to={prop.to} key={key} />;
}
return (
<Route
exact
path={prop.path}
component={prop.component}
key={key}
/>
);
})}
</Switch>
</div>
</MuiThemeProvider>
</div>
);
}
return (
<div className={classes.root} ref="root">
<CssBaseline />
<MuiThemeProvider theme={this.state.theme}>
<Header
handleDrawerToggle={handleDrawerToggle}
location={this.props.location}
/>
<Sidebar
handleDrawerToggle={handleDrawerToggle}
open={this.state.mobileOpen}
location={this.props.location}
/>
<div className={classes.content}>
<div className={classes.toolbar} />
<Switch>
{viewRoutes.map((prop, key) => {
if (prop.redirect) {
return <Redirect from={prop.path} to={prop.to} key={key} />;
}
return (
<Route
exact
path={prop.path}
component={prop.component}
key={key}
/>
);
})}
</Switch>
</div>
</MuiThemeProvider>
</div>
);
}
}
DefaultLayout.propTypes = {
classes: PropTypes.object.isRequired,
devicesById: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
devicesById: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
const { devicesById, schemas } = state;
const { devicesById, schemas } = state;
return {
devicesById,
schemas,
};
return {
devicesById,
schemas,
};
}
export default connect(mapStateToProps)(
withStyles(dashboardStyle)(DefaultLayout)
);
export default connect(mapStateToProps)(withStyles(dashboardStyle)(DefaultLayout));

View File

@ -1,4 +1,4 @@
import { drawerWidth } from "../../assets/jss/style";
import { drawerWidth } from "assets/jss/style";
const appStyle = (theme) => ({
root: {
@ -9,7 +9,7 @@ const appStyle = (theme) => ({
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing.unit * 3,
padding: theme.spacing(3),
minWidth: 200,
[theme.breakpoints.up("md")]: {
marginLeft: drawerWidth,

View File

@ -0,0 +1,7 @@
import { api } from 'utils/api';
export function getSystemConfig() {
return api.get('/config').then(response => {
return response.data.config;
});
}

View File

@ -0,0 +1,47 @@
import { api } from 'utils/api';
export function getDevices() {
return api.get('/devices').then(response => {
const devices = response.data.devices;
return Object.keys(devices).map(key => {
return {
key: key,
id: key,
name: devices[key].name,
config: devices[key],
};
});
});
}
export function deleteDevice(device_id) {
return api.delete(`/devices/${device_id}`);
}
export function updateDevice(config) {
return api.put('/devices', config);
}
export function createDevice(config) {
return api.post('/devices', config);
}
export function getDevice(device_id) {
return api.get(`/devices/${device_id}`).then(response => {
const device = response.data;
return {
key: device_id,
id: device_id,
name: device.name,
config: device,
};
});
}
export function getDeviceEffects(device_id) {
return api.get(`devices/${device_id}/effects`);
}
export function deleteDeviceEffects(device_id) {
return api.delete(`devices/${device_id}/effects`);
}

View File

@ -6,7 +6,7 @@ import {
RECEIVE_DEVICE_UPDATE,
RECEIVE_DEVICE_EFFECT_UPDATE,
RECEIVE_DEVICE_ENTRY
} from '../actions'
} from 'actions'
function device(
state = {

View File

@ -1,6 +1,6 @@
import {
GET_PRESETS
} from '../actions'
} from 'actions'
export function presets(state = {}, action) {
switch (action.type) {

View File

@ -1,7 +1,6 @@
import { combineReducers } from 'redux'
import {
RECEIVE_SCHEMAS,
} from '../actions'
} from 'actions'
export function schemas(state = {}, action) {
switch (action.type) {

View File

@ -1,7 +1,7 @@
import {
GET_AUDIO_INPUTS,
SET_AUDIO_INPUT
} from '../actions'
// SET_AUDIO_INPUT
} from 'actions'
export function settings(state = {}, action) {
console.log(action)

View File

@ -1,53 +1,58 @@
import axios from "axios";
import axios from 'axios';
const url = window.location.protocol + '//' + window.location.host + '/api/';
// const url = window.location.protocol + '//' + window.location.host + '/api/';
const baseURL = '/api';
function callApi(method, api, data) {
return axios({
method: method,
url: url + api,
data: data
});
}
// function callApi(method, api, data) {
// return axios({
// method: method,
// url: url + api,
// data: data,
// });
// }
function getDevices() {
return callApi('get', 'devices').then(response => {
const devices = response.data.devices
return Object.keys(devices).map(key => {
return {
key: key,
id: key,
name: devices[key].name,
config: devices[key]
}
})
})
}
// function getDevices() {
// return callApi('get', 'devices').then(response => {
// const devices = response.data.devices;
// return Object.keys(devices).map(key => {
// return {
// key: key,
// id: key,
// name: devices[key].name,
// config: devices[key],
// };
// });
// });
// }
function deleteDevice(device_id) {
return callApi('delete', 'devices/' + device_id)
}
// function deleteDevice(device_id) {
// return callApi('delete', 'devices/' + device_id);
// }
function addDevice(config) {
return callApi('put', 'devices', config)
}
// function addDevice(config) {
// return callApi('put', 'devices', config);
// }
function getDevice(device_id) {
return callApi('get', 'devices/' + device_id).then(response => {
const device = response.data
return {
key: device_id,
id: device_id,
name: device.name,
config: device
}
})
}
// function getDevice(device_id) {
// return callApi('get', 'devices/' + device_id).then(response => {
// const device = response.data;
// return {
// key: device_id,
// id: device_id,
// name: device.name,
// config: device,
// };
// });
// }
function getDeviceEffects(device_id) {
return callApi('get', 'devices/' + device_id + '/effects').then(response => {
return response.data;
})
}
// function getDeviceEffects(device_id) {
// return callApi('get', 'devices/' + device_id + '/effects').then(response => {
// return response.data;
// });
// }
export { callApi, getDevices, deleteDevice, addDevice, getDevice, getDeviceEffects }
// export { callApi, getDevices, deleteDevice, addDevice, getDevice, getDeviceEffects };
export const api = axios.create({
baseURL,
});

View File

@ -5,14 +5,11 @@ import withStyles from "@material-ui/core/styles/withStyles";
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import Typography from '@material-ui/core/Typography';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import Grid from "@material-ui/core/Grid";
import PixelColorGraph from "../../components/PixelColorGraph/PixelColorGraph";
import DeviceMiniControl from '../../components/DeviceMiniControl/DeviceMiniControl';
import AddPresetCard from "../../components/AddPresetCard/AddPresetCard";
import PixelColorGraph from "components/PixelColorGraph/PixelColorGraph";
import DeviceMiniControl from 'components/DeviceMiniControl/DeviceMiniControl';
import AddPresetCard from "components/AddPresetCard/AddPresetCard";
const styles = theme => ({
root: {
@ -35,7 +32,7 @@ class DashboardView extends React.Component {
render() {
const { classes, devicesById } = this.props;
if (Object.keys(devicesById) == 0)
if (Object.keys(devicesById) === 0)
{
return (
<div>

View File

@ -1,38 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import React from 'react';
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Grid from '@material-ui/core/Grid';
import MelbankGraph from "../../components/MelbankGraph/MelbankGraph.jsx";
import MelbankGraph from 'components/MelbankGraph/MelbankGraph.jsx';
class DeveloperView extends React.Component {
render() {
const { graphString } = this.props.match.params;
componentDidMount() {
const { device_id } = this.props.match.params;
}
let graphList = graphString.split('+');
let graphDom = Object.keys(graphList).map(graphIndex => {
return (
<Grid item xs={12}>
<p>{graphList[graphIndex].replace(/^\w/, c => c.toUpperCase())} Graph</p>
<MelbankGraph key={graphIndex} graphId={graphList[graphIndex]} />
</Grid>
);
});
render() {
const { classes } = this.props;
const { graphString } = this.props.match.params;
let graphList = graphString.split("+")
let graphDom = Object.keys(graphList).map(graphIndex => {
return (
<Grid item xs={12}>
<p>{graphList[graphIndex].replace(/^\w/, c => c.toUpperCase())} Graph</p>
<MelbankGraph key={graphIndex} graphId={graphList[graphIndex]}/>
</Grid>
);
});
return (
<Grid container spacing={24}>
{graphDom}
</Grid>
);
}
return (
<Grid container spacing={3}>
{graphDom}
</Grid>
);
}
}
export default DeveloperView;

View File

@ -1,113 +1,108 @@
import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Grid from '@material-ui/core/Grid';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import { callApi, getDevice, getDeviceEffects} from "../../utils/api";
import EffectControl from "../../components/EffectControl/EffectControl.jsx";
import PixelColorGraph from "../../components/PixelColorGraph/PixelColorGraph.jsx";
import { getDevice, getDeviceEffects } from 'proxies/device';
import EffectControl from 'components/EffectControl/EffectControl.jsx';
import PixelColorGraph from 'components/PixelColorGraph/PixelColorGraph.jsx';
class DeviceView extends React.Component {
constructor() {
super();
this.state = {
device : null,
effect : null
};
}
componentDidMount() {
const { device_id } = this.props.match.params;
this.state.device = null;
getDevice(device_id)
.then(device => {
this.setState({ device: device });
})
.catch(error => console.log(error));
this.state.effect = null;
getDeviceEffects(device_id)
.then(effect => {
this.setState({ effect: effect });
})
.catch(error => console.log(error));
}
componentWillReceiveProps(nextProps) {
var device = null;
if (this.props.devicesById)
{
this.state.device = null;
device = this.props.devicesById[nextProps.match.params.device_id]
this.setState(...this.state, {device: device});
constructor() {
super();
this.state = {
device: null,
effect: null,
};
}
if(device !== undefined && device !== null)
{
this.state.effect = null;
getDeviceEffects(device.id)
.then(effect => {
this.setState({ effect: effect });
})
.catch(error => console.log(error));
}
}
componentDidMount() {
const { device_id } = this.props.match.params;
render() {
const { classes } = this.props;
const { device_id } = this.props.match.params;
const { device, effect } = this.state;
// this.state.device = null;
getDevice(device_id)
.then(response => {
console.log('what the device here', response);
this.setState({ device: response });
})
.catch(error => console.log(error));
if (device)
{
return (
<Grid container direction="row" spacing={4}>
{renderPixelGraph(device, effect)}
<Grid item xs={12}>
<Card>
<CardContent>
<EffectControl device={device} effect={effect}/>
</CardContent>
</Card>
</Grid>
</Grid>
);
// this.state.effect = null;
getDeviceEffects(device_id)
.then(response => {
this.setState({ effect: response.data });
})
.catch(error => console.log(error));
}
componentWillReceiveProps(nextProps) {
var device = null;
if (this.props.devicesById) {
// this.state.device = null;
console.log('whats going on here', this.props);
device = this.props.devicesById[nextProps.match.params.device_id];
this.setState({ device });
}
if (device !== undefined && device !== null) {
// this.state.effect = null;
getDeviceEffects(device.id)
.then(response => {
this.setState({ effect: response.data });
})
.catch(error => console.log(error));
}
}
render() {
const { device, effect } = this.state;
if (device) {
return (
<Grid container direction="row" spacing={4}>
{renderPixelGraph(device, effect)}
<Grid item xs={12}>
<Card>
<CardContent>
<EffectControl device={device} effect={effect} />
</CardContent>
</Card>
</Grid>
</Grid>
);
}
return <p>Loading</p>;
}
return (<p>Loading</p>)
}
}
const renderPixelGraph = (device, effect) => {
if (device.effect && device.effect.name) {
console.log(effect)
return (
<Grid item xs={12}>
<Card>
<CardContent>
<PixelColorGraph device={device}/>
</CardContent>
</Card>
</Grid>
)
}
}
if (device.effect && device.effect.name) {
console.log(effect);
return (
<Grid item xs={12}>
<Card>
<CardContent>
<PixelColorGraph device={device} />
</CardContent>
</Card>
</Grid>
);
}
};
DeviceView.propTypes = {
devicesById: PropTypes.object.isRequired,
devicesById: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
const { devicesById } = state
const { devicesById } = state;
return {
devicesById
}
return {
devicesById,
};
}
export default connect(mapStateToProps)(DeviceView);
export default connect(mapStateToProps)(DeviceView);

View File

@ -1,20 +1,14 @@
import React from "react";
import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles";
import Typography from '@material-ui/core/Typography';
//import Slider from '@material-ui/core/Slider';
import Input from '@material-ui/core/Input';
import { connect } from "react-redux";
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import AddIcon from "@material-ui/icons/Add";
import DevicesTable from "../../components/DevicesTable/DevicesTable.jsx";
import DeviceConfigDialog from "../../components/DeviceConfigDialog/DeviceConfigDialog.jsx";
import DevicesTable from "components/DevicesTable/DevicesTable.jsx";
import DeviceConfigDialog from "components/DeviceConfigDialog/DeviceConfigDialog.jsx";
const styles = theme => ({
cardResponsive: {
@ -41,18 +35,18 @@ class DevicesView extends React.Component {
}
openAddDeviceDialog = () => {
this.setState(...this.state, { addDialogOpened: true });
this.setState({ addDialogOpened: true });
};
closeAddDeviceDialog = () => {
this.setState(...this.state, { addDialogOpened: false });
this.setState({ addDialogOpened: false });
};
render() {
const { classes, schemas } = this.props;
const { classes } = this.props;
return (
<div>
<Grid container spacing={16}>
<Grid container spacing={2}>
<Grid item xs={12} sm={12} md={12}>
<Card>
<CardContent>

View File

@ -1,76 +1,62 @@
import React from "react";
import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles/withStyles";
import React from 'react';
import withStyles from '@material-ui/core/styles/withStyles';
import Typography from '@material-ui/core/Typography';
// import Slider from '@material-ui/core/Slider';
import Input from '@material-ui/core/Input';
import { connect } from "react-redux";
import { connect } from 'react-redux';
import Grid from "@material-ui/core/Grid";
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import AddIcon from "@material-ui/icons/Add";
import Grid from '@material-ui/core/Grid';
import PresetsCard from "components/PresetCard/PresetCard.jsx";
import PresetsConfigDialog from "components/PresetConfigDialog/PresetConfigDialog.jsx";
import AddPresetCard from "components/AddPresetCard/AddPresetCard";
import { getPresets } from '../../actions';
import { includeKeyInObject } from '../../utils/helpers';
import PresetsCard from 'components/PresetCard/PresetCard.jsx';
import AddPresetCard from 'components/AddPresetCard/AddPresetCard';
import { getPresets } from 'actions';
import { includeKeyInObject } from 'utils/helpers';
const styles = theme => ({
cardResponsive: {
width: "100%",
overflowX: "auto"
},
button: {
position: "absolute",
bottom: theme.spacing.unit * 2,
right: theme.spacing.unit * 2
},
dialogButton: {
float: "right"
}
cardResponsive: {
width: '100%',
overflowX: 'auto',
},
button: {
position: 'absolute',
bottom: theme.spacing.unit * 2,
right: theme.spacing.unit * 2,
},
dialogButton: {
float: 'right',
},
});
class PresetsView extends React.Component {
constructor(props) {
super(props);
}
componentDidMount = () => {
this.props.getPresets();
};
componentDidMount = () => {
this.props.getPresets()
}
render() {
const { classes } = this.props;
return (
<div>
<Grid container direction="row" spacing={4}>
<Grid item xs={12}>
<AddPresetCard />
</Grid>
<Grid item xs={12}>
<React.Fragment>
{renderPresets(this.props.presets)}
</React.Fragment>
</Grid>
</Grid>
</div>
);
}
render() {
return (
<div>
<Grid container direction="row" spacing={4}>
<Grid item xs={12}>
<AddPresetCard />
</Grid>
<Grid item xs={12}>
<React.Fragment>{renderPresets(this.props.presets)}</React.Fragment>
</Grid>
</Grid>
</div>
);
}
}
const renderPresets = (presets) => Object.keys(presets).map((key) => (<PresetsCard key={key} preset={includeKeyInObject(key, presets[key])} />))
const renderPresets = presets =>
Object.keys(presets).map(key => (
<PresetsCard key={key} preset={includeKeyInObject(key, presets[key])} />
));
const mapStateToProps = state => ({
presets: state.presets,
});
const mapStateToProps = state => ({
presets: state.presets
})
const mapDispatchToProps = dispatch => ({
getPresets: () => dispatch(getPresets()),
});
const mapDispatchToProps = (dispatch) => ({
getPresets: () => dispatch(getPresets())
})
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(PresetsView));
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(PresetsView));

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -0,0 +1,22 @@
{
"files": {
"main.css": "/static/css/main.e245df3b.chunk.css",
"main.js": "/static/js/main.f02fceaa.chunk.js",
"main.js.map": "/static/js/main.f02fceaa.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.a0387bbe.js",
"runtime-main.js.map": "/static/js/runtime-main.a0387bbe.js.map",
"static/js/2.7d458906.chunk.js": "/static/js/2.7d458906.chunk.js",
"static/js/2.7d458906.chunk.js.map": "/static/js/2.7d458906.chunk.js.map",
"index.html": "/index.html",
"precache-manifest.95c57393ff9cfaedb32397d9383c3121.js": "/precache-manifest.95c57393ff9cfaedb32397d9383c3121.js",
"service-worker.js": "/service-worker.js",
"static/css/main.e245df3b.chunk.css.map": "/static/css/main.e245df3b.chunk.css.map",
"static/js/2.7d458906.chunk.js.LICENSE.txt": "/static/js/2.7d458906.chunk.js.LICENSE.txt"
},
"entrypoints": [
"static/js/runtime-main.a0387bbe.js",
"static/js/2.7d458906.chunk.js",
"static/css/main.e245df3b.chunk.css",
"static/js/main.f02fceaa.chunk.js"
]
}

View File

@ -1,100 +0,0 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/static/";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./ledfx/frontend/index.jsx");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./ledfx/frontend/index.jsx":
/*!**********************************!*\
!*** ./ledfx/frontend/index.jsx ***!
\**********************************/
/*! no static exports found */
/***/ (function(module, exports) {
eval("throw new Error(\"Module build failed (from ./node_modules/babel-loader/lib/index.js):\\nError: Plugin/Preset files are not allowed to export objects, only functions. In /Users/dakotapeel/Dev/LedFx/node_modules/babel-preset-es2015/lib/index.js\\n at createDescriptor (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-descriptors.js:178:11)\\n at /Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-descriptors.js:109:50\\n at Array.map (<anonymous>)\\n at createDescriptors (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-descriptors.js:109:29)\\n at createPresetDescriptors (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-descriptors.js:101:10)\\n at /Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-descriptors.js:58:104\\n at cachedFunction (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/caching.js:62:27)\\n at cachedFunction.next (<anonymous>)\\n at evaluateSync (/Users/dakotapeel/Dev/LedFx/node_modules/gensync/index.js:244:28)\\n at sync (/Users/dakotapeel/Dev/LedFx/node_modules/gensync/index.js:84:14)\\n at presets (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-descriptors.js:29:84)\\n at mergeChainOpts (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-chain.js:320:26)\\n at /Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-chain.js:283:7\\n at Generator.next (<anonymous>)\\n at buildRootChain (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/config-chain.js:68:36)\\n at buildRootChain.next (<anonymous>)\\n at loadPrivatePartialConfig (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/partial.js:95:62)\\n at loadPrivatePartialConfig.next (<anonymous>)\\n at Function.<anonymous> (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/partial.js:120:25)\\n at Generator.next (<anonymous>)\\n at evaluateSync (/Users/dakotapeel/Dev/LedFx/node_modules/gensync/index.js:244:28)\\n at Function.sync (/Users/dakotapeel/Dev/LedFx/node_modules/gensync/index.js:84:14)\\n at Object.<anonymous> (/Users/dakotapeel/Dev/LedFx/node_modules/@babel/core/lib/config/index.js:41:61)\\n at Object.<anonymous> (/Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:151:26)\\n at Generator.next (<anonymous>)\\n at asyncGeneratorStep (/Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:3:103)\\n at _next (/Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:5:194)\\n at /Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:5:364\\n at new Promise (<anonymous>)\\n at Object.<anonymous> (/Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:5:97)\\n at Object._loader (/Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:231:18)\\n at Object.loader (/Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:64:18)\\n at Object.<anonymous> (/Users/dakotapeel/Dev/LedFx/node_modules/babel-loader/lib/index.js:59:12)\");//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9sZWRmeC9mcm9udGVuZC9pbmRleC5qc3guanMiLCJzb3VyY2VzIjpbXSwibWFwcGluZ3MiOiIiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ledfx/frontend/index.jsx\n");
/***/ })
/******/ });

BIN
ledfx_frontend/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,22 +1 @@
<!DOCTYPE html>
<html>
<head>
<title>LedFx</title>
<link rel="stylesheet" type="text/css" href="{{ url('static', filename='./style.css') }}"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"/>
<!-- Mobile App Support -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<link rel="icon" sizes="128x128" href="{{ url('static', filename='./small_black_alpha.png') }}">
</head>
<body>
<div id="main"></div>
<script type="text/javascript" src="{{ url('static', filename='./bundle.js') }}"></script>
</body>
</html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500"/><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="mobile-web-app-capable" content="yes"><link rel="apple-touch-icon" href="/ledfx_icon.png"/><link rel="icon" href="/favicon.ico"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>LedFx</title><link href="/static/css/main.e245df3b.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,f=r[0],i=r[1],a=r[2],c=0,s=[];c<f.length;c++)l=f[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,f=1;f<t.length;f++){var i=t[f];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var f=this.webpackJsonpLedFx=this.webpackJsonpLedFx||[],i=f.push.bind(f);f.push=r,f=f.slice();for(var a=0;a<f.length;a++)r(f[a]);var p=i;t()}([])</script><script src="/static/js/2.7d458906.chunk.js"></script><script src="/static/js/main.f02fceaa.chunk.js"></script></body></html>

BIN
ledfx_frontend/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
ledfx_frontend/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,25 @@
{
"short_name": "Led FX",
"name": "Led FX",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,26 @@
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "458b864ea1a51b50ac5b5a0624a105b1",
"url": "/index.html"
},
{
"revision": "9507b79bf8629864dd2a",
"url": "/static/css/main.e245df3b.chunk.css"
},
{
"revision": "655ffe6775863b899422",
"url": "/static/js/2.7d458906.chunk.js"
},
{
"revision": "af5111307236c4c69d6adba51f98588a",
"url": "/static/js/2.7d458906.chunk.js.LICENSE.txt"
},
{
"revision": "9507b79bf8629864dd2a",
"url": "/static/js/main.f02fceaa.chunk.js"
},
{
"revision": "0a67f13dd3aa04f6fdf4",
"url": "/static/js/runtime-main.a0387bbe.js"
}
]);

View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -0,0 +1,39 @@
/**
* Welcome to your Workbox-powered service worker!
*
* You'll need to register this file in your web app and you should
* disable HTTP caching for this file too.
* See https://goo.gl/nhQhGp
*
* The rest of the code is auto-generated. Please don't update this file
* directly; instead, make changes to your Workbox build configuration
* and re-run your build process.
* See https://goo.gl/2aRDsh
*/
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
importScripts(
"/precache-manifest.95c57393ff9cfaedb32397d9383c3121.js"
);
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
workbox.core.clientsClaim();
/**
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("/index.html"), {
blacklist: [/^\/_/,/\/[^/?]+\.[^/]+$/],
});

View File

@ -0,0 +1,2 @@
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}body,html{font-family:"Roboto","Helvetica",sans-serif;font-weight:300}
/*# sourceMappingURL=main.e245df3b.chunk.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sources":["index.css","style.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,mJAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,yEAEF,CCZA,UACE,2CAA8C,CAC9C,eACF","file":"main.e245df3b.chunk.css","sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n}\n","html, body {\n font-family: 'Roboto', 'Helvetica', sans-serif;\n font-weight: 300;\n}"]}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,87 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/*!
Copyright (c) 2017 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/*!
* Chart.js v2.9.3
* https://www.chartjs.org
* (c) 2019 Chart.js Contributors
* Released under the MIT License
*/
/**
* A better abstraction over CSS.
*
* @copyright Oleg Isonen (Slobodskoi) / Isonen 2014-present
* @website https://github.com/cssinjs/jss
* @license MIT
*/
/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**!
* @fileOverview Kickass library to create and place poppers near their reference elements.
* @version 1.16.1
* @license
* Copyright (c) 2016 Federico Zivolo and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
!function(e){function r(r){for(var n,l,f=r[0],i=r[1],a=r[2],c=0,s=[];c<f.length;c++)l=f[c],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,a||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,f=1;f<t.length;f++){var i=t[f];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var f=this.webpackJsonpLedFx=this.webpackJsonpLedFx||[],i=f.push.bind(f);f.push=r,f=f.slice();for(var a=0;a<f.length;a++)r(f[a]);var p=i;t()}([]);
//# sourceMappingURL=runtime-main.a0387bbe.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,4 +0,0 @@
html, body {
font-family: 'Roboto', 'Helvetica', sans-serif;
font-weight: 300;
}

View File

@ -47,7 +47,7 @@ setup(
]
},
package_data={
'frontend/build':['*'],
'ledfx_frontend':['*'],
'': ['*.npy']
},