Skip to content

Commit c404da6

Browse files
authored
Merge pull request #297 from OpenEnergyDashboard/development
Update master to 0.3.0
2 parents 28001d3 + a60f1b3 commit c404da6

File tree

94 files changed

+3426
-944
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+3426
-944
lines changed

package-lock.json

Lines changed: 1204 additions & 346 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
22
"name": "Open-Energy-Dashboard",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"private": false,
55
"license": "MPL-2.0",
66
"scripts": {
77
"start": "node ./src/bin/www",
88
"dev": "webpack -d --watch --color --progress",
99
"build": "cross-env NODE_ENV=production webpack -p",
1010
"checkHeader": "./src/scripts/checkHeader.sh",
11-
"lint": "./node_modules/.bin/eslint src/client/app/**/*.js src/client/app/**/*.jsx src/server/**/*.js src/server/**/*.jsx",
11+
"lint": "./node_modules/.bin/eslint src/client/app/**/*.js src/client/app/**/*.jsx src/server/**/*.js src/server/*.js",
1212
"test": "./node_modules/.bin/mocha \"src/server/test/**/*.js\"",
1313
"createdb": "node ./src/server/services/createDB.js",
1414
"addMamacMeters": "node ./src/server/services/addMamacMeters.js",
@@ -25,6 +25,7 @@
2525
"babel-preset-react": "~6.24.1",
2626
"bcryptjs": "~2.4.3",
2727
"body-parser": "~1.15.1",
28+
"bootstrap": "~4.0.0",
2829
"chart.js": "~2.7.0",
2930
"chartjs-plugin-datalabels": "~0.1.0",
3031
"cookie-parser": "~1.4.3",
@@ -39,23 +40,26 @@
3940
"lodash-webpack-plugin": "~0.11.4",
4041
"moment": "~2.19.1",
4142
"morgan": "~1.7.0",
43+
"multer": "~1.3.0",
4244
"nodemailer": "~2.6.4",
4345
"pg-promise": "~5.9.7",
4446
"prop-types": "~15.5.10",
4547
"react": "~15.6.1",
46-
"react-bootstrap": "~0.31.3",
4748
"react-chartjs-2": "~2.6.2",
4849
"react-dom": "~15.6.1",
50+
"react-dropzone": "~4.2.3",
4951
"react-notification-system": "~0.2.15",
5052
"react-rangeslider": "~2.2.0",
5153
"react-redux": "~5.0.6",
5254
"react-router": "~3.0.5",
5355
"react-select": "~1.0.0-rc.10",
56+
"reactstrap": "~5.0.0-alpha.4",
5457
"redux": "~3.7.2",
5558
"redux-thunk": "~2.2.0",
5659
"request": "~2.83.0",
5760
"request-promise-native": "~1.0.5",
5861
"serve-favicon": "~2.3.0",
62+
"stream-buffers": "~3.0.1",
5963
"webpack": "~3.7.1",
6064
"xml2js": "~0.4.19"
6165
},

src/bin/www

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
const app = require('../server/app');
1212
const http = require('http');
13-
const log = require('../server/log');
13+
const { log } = require('../server/log');
1414

1515
const serverPort = require('../server/config').serverPort;
1616

@@ -66,11 +66,11 @@ function onError(error) {
6666
// handle specific listen errors with friendly messages
6767
switch (error.code) {
6868
case 'EACCES':
69-
log(`${bind} requires elevated privileges`, 'error', true);
69+
log.error(`${bind} requires elevated privileges`);
7070
process.exit(1);
7171
break;
7272
case 'EADDRINUSE':
73-
log(`${bind} is already in use`, 'error', true);
73+
log.error(`${bind} is already in use`);
7474
process.exit(1);
7575
break;
7676
default:
@@ -87,7 +87,7 @@ function onListening() {
8787
const bind = typeof addr === 'string'
8888
? `pipe ${addr}`
8989
: `port ${addr.port}`;
90-
log(`Listening on ${bind}`);
90+
log.info(`Listening on ${bind}`);
9191
}
9292

9393

src/client/app/actions/admin.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import axios from 'axios';
6+
import { changeBarStacking, changeChartToRender } from './graph';
7+
import { showErrorNotification, showSuccessNotification } from '../utils/notifications';
8+
import { getToken } from '../utils/token';
9+
10+
export const UPDATE_IMPORT_METER = 'UPDATE_IMPORT_METER';
11+
export const UPDATE_DISPLAY_TITLE = 'UPDATE_DISPLAY_TITLE';
12+
export const UPDATE_DEFAULT_CHART_TO_RENDER = 'UPDATE_DEFAULT_CHART_TO_RENDER';
13+
export const TOGGLE_DEFAULT_BAR_STACKING = 'TOGGLE_DEFAULT_BAR_STACKING';
14+
export const REQUEST_PREFERENCES = 'REQUEST_PREFERENCES';
15+
export const RECEIVE_PREFERENCES = 'RECEIVE_PREFERENCES';
16+
export const MARK_PREFERENCES_NOT_SUBMITTED = 'MARK_PREFERENCES_NOT_SUBMITTED';
17+
export const MARK_PREFERENCES_SUBMITTED = 'MARK_PREFERENCES_SUBMITTED';
18+
19+
export function updateDisplayTitle(displayTitle) {
20+
return { type: UPDATE_DISPLAY_TITLE, displayTitle };
21+
}
22+
23+
export function updateDefaultChartToRender(defaultChartToRender) {
24+
return { type: UPDATE_DEFAULT_CHART_TO_RENDER, defaultChartToRender };
25+
}
26+
27+
export function toggleDefaultBarStacking() {
28+
return { type: TOGGLE_DEFAULT_BAR_STACKING };
29+
}
30+
31+
function requestPreferences() {
32+
return { type: REQUEST_PREFERENCES };
33+
}
34+
35+
function receivePreferences(data) {
36+
return { type: RECEIVE_PREFERENCES, data };
37+
}
38+
39+
function markPreferencesSubmitted() {
40+
return { type: MARK_PREFERENCES_SUBMITTED };
41+
}
42+
43+
function markPreferencesNotSubmitted() {
44+
return { type: MARK_PREFERENCES_NOT_SUBMITTED };
45+
}
46+
47+
function fetchPreferences() {
48+
return (dispatch, getState) => {
49+
dispatch(requestPreferences());
50+
return axios.get('/api/preferences')
51+
.then(response => {
52+
dispatch(receivePreferences(response.data));
53+
const state = getState();
54+
if (!state.graph.hotlinked) {
55+
dispatch(changeChartToRender(state.admin.defaultChartToRender));
56+
if (response.data.defaultBarStacking !== state.graph.barStacking) {
57+
dispatch(changeBarStacking());
58+
}
59+
}
60+
});
61+
};
62+
}
63+
64+
function submitPreferences() {
65+
return (dispatch, getState) => {
66+
const state = getState();
67+
dispatch(markPreferencesSubmitted());
68+
return axios.post('/api/preferences',
69+
{
70+
token: getToken(),
71+
preferences: {
72+
displayTitle: state.admin.displayTitle,
73+
defaultChartToRender: state.admin.defaultChartToRender,
74+
defaultBarStacking: state.admin.defaultBarStacking
75+
}
76+
})
77+
.then(() => {
78+
showSuccessNotification('Updated preferences');
79+
})
80+
.catch(() => {
81+
dispatch(markPreferencesNotSubmitted());
82+
showErrorNotification('Failed to submit changes');
83+
}
84+
);
85+
};
86+
}
87+
88+
function shouldFetchPreferenceData(state) {
89+
return !state.admin.isFetching;
90+
}
91+
92+
function shouldSubmitPreferenceData(state) {
93+
return !state.admin.submitted;
94+
}
95+
96+
export function fetchPreferencesIfNeeded() {
97+
return (dispatch, getState) => {
98+
if (shouldFetchPreferenceData(getState())) {
99+
return dispatch(fetchPreferences());
100+
}
101+
return Promise.resolve();
102+
};
103+
}
104+
105+
export function submitPreferencesIfNeeded() {
106+
return (dispatch, getState) => {
107+
if (shouldSubmitPreferenceData(getState())) {
108+
return dispatch(submitPreferences());
109+
}
110+
return Promise.resolve();
111+
};
112+
}
113+
114+
export function updateSelectedMeter(meterID) {
115+
return { type: UPDATE_IMPORT_METER, meterID };
116+
}

src/client/app/actions/barReadings.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function fetchCompareReadings(meterIDs, timeInterval) {
124124
dispatch(requestMeterBarReadings(meterIDs, timeInterval, compareDuration));
125125
const stringifiedMeterIDs = meterIDs.join(',');
126126
return axios.get(`/api/readings/bar/meters/${stringifiedMeterIDs}`, {
127-
params: { timeInterval: timeInterval.toString(), barDuration: compareDuration.toISOString() }
127+
params: { timeInterval: timeInterval, barDuration: compareDuration.toISOString() }
128128
}).then(response => dispatch(receiveMeterBarReadings(meterIDs, timeInterval, compareDuration, response.data)));
129129
};
130130
}
@@ -133,11 +133,11 @@ function fetchGroupCompareReadings(groupIDs, timeInterval) {
133133
return (dispatch, getState) => {
134134
const compareDuration = getState().graph.compareDuration;
135135
dispatch(requestGroupBarReadings(groupIDs, timeInterval, compareDuration));
136-
// API expectes a comma-seperated string of IDs
136+
// API expects a comma-separated string of IDs
137137
const stringifiedIDs = groupIDs.join(',');
138138

139139
return axios.get(`/api/readings/bar/groups/${stringifiedIDs}`, {
140-
params: { timeInterval: timeInterval.toString(), barDuration: compareDuration.toISOString() }
140+
params: { timeInterval: timeInterval, barDuration: compareDuration.toISOString() }
141141
}).then(response => dispatch(receiveGroupBarReadings(groupIDs, timeInterval, compareDuration, response.data)));
142142
};
143143
}

src/client/app/actions/graph.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ export const UPDATE_BAR_DURATION = 'UPDATE_BAR_DURATION';
1515
export const CHANGE_CHART_TO_RENDER = 'CHANGE_CHART_TO_RENDER';
1616
export const CHANGE_BAR_STACKING = 'CHANGE_BAR_STACKING';
1717
export const CHANGE_GRAPH_ZOOM = 'CHANGE_GRAPH_ZOOM';
18+
export const UPDATE_COMPARE_INTERVAL = 'UPDATE_COMPARE_INTERVAL';
19+
export const UPDATE_COMPARE_DURATION = 'UPDATE_COMPARE_DURATION';
20+
export const TOGGLE_HOTLINKED = 'TOGGLE_HOTLINKED';
21+
22+
23+
function toggleHotlinked() {
24+
return { type: 'TOGGLE_HOTLINKED' };
25+
}
1826

1927
/**
2028
* @param {string} chartType is one of chartTypes
@@ -48,6 +56,23 @@ export function changeBarDuration(barDuration) {
4856
};
4957
}
5058

59+
function updateCompareTimeInterval(compareTimeInterval) {
60+
return { type: UPDATE_COMPARE_INTERVAL, compareTimeInterval };
61+
}
62+
63+
function updateCompareDuration(compareDuration) {
64+
return { type: UPDATE_COMPARE_DURATION, compareDuration };
65+
}
66+
67+
export function changeCompareTimeInterval(compareTimeInterval, compareDuration) {
68+
return (dispatch, getState) => {
69+
dispatch(updateCompareTimeInterval(compareTimeInterval));
70+
dispatch(updateCompareDuration(compareDuration));
71+
dispatch(fetchNeededCompareReadings(getState().graph.compareTimeInterval));
72+
return Promise.resolve();
73+
};
74+
}
75+
5176
export function changeSelectedMeters(meterIDs) {
5277
return (dispatch, getState) => {
5378
dispatch(updateSelectedMeters(meterIDs));
@@ -104,7 +129,7 @@ export function changeGraphZoomIfNeeded(timeInterval) {
104129
* @returns {function(*)}
105130
*/
106131
export function changeOptionsFromLink(options) {
107-
const dispatchFirst = [];
132+
const dispatchFirst = [toggleHotlinked()];
108133
const dispatchSecond = [];
109134
if (options.meterIDs) {
110135
dispatchFirst.push(fetchMetersDetailsIfNeeded());

src/client/app/actions/groups.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
*/
66

77
import axios from 'axios';
8-
import getToken from '../utils/getToken';
8+
import { getToken } from '../utils/token';
9+
import { showErrorNotification } from '../utils/notifications';
910

1011
// View and fetching actions
1112
export const REQUEST_GROUPS_DETAILS = 'REQUEST_GROUPS_DETAILS';
@@ -277,9 +278,9 @@ function submitNewGroup(group) {
277278
dispatch2(changeDisplayMode(DISPLAY_MODE.VIEW));
278279
});
279280
})
280-
.catch(error => {
281+
.catch(() => {
281282
dispatch(markGroupInEditingNotSubmitted());
282-
console.error(error);
283+
showErrorNotification('Failed to create a new group');
283284
});
284285
};
285286
}
@@ -296,9 +297,13 @@ function submitGroupEdits(group) {
296297
dispatch2(changeDisplayMode(DISPLAY_MODE.VIEW));
297298
});
298299
})
299-
.catch(error => {
300+
.catch(e => {
300301
dispatch(markGroupInEditingNotSubmitted());
301-
console.error(error);
302+
if (e.response.data.message && e.response.data.message === 'Cyclic group detected') {
303+
showErrorNotification('You cannot create a cyclic group');
304+
} else {
305+
showErrorNotification('Failed to edit group');
306+
}
302307
});
303308
};
304309
}
@@ -354,6 +359,8 @@ export function deleteGroup() {
354359
dispatch2(changeDisplayMode('view'));
355360
});
356361
})
357-
.catch(console.error);
362+
.catch(() => {
363+
showErrorNotification('Failed to delete group');
364+
});
358365
};
359366
}

src/client/app/actions/meters.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function fetchMetersDetails() {
2828
}
2929

3030
/**
31-
* @param {State} state
31+
* @param {State} Redux state
3232
*/
3333
function shouldFetchMetersDetails(state) {
3434
return !state.meters.isFetching && state.meters.meters === undefined;

0 commit comments

Comments
 (0)