-
Notifications
You must be signed in to change notification settings - Fork 252
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Export group #83
Export group #83
Changes from 18 commits
aef9792
d3bb015
e381bd2
5f9996a
5e811fa
c3f6752
7783382
950b045
1d56556
539401e
d610906
eda9804
ff4f005
199d31d
5082823
b659757
c3fc89f
3ae6e54
40dea5e
9db2746
3c22a47
6c0937f
dc03958
538b85c
c91b9a6
16f4e3a
4c6b4ec
a8ca745
394c155
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
import moment from 'moment'; | ||
|
||
/** | ||
* Function to converts the compressed meter data into a CSV formatted string. | ||
* @param items The compressed meter data. | ||
* @returns output A string containing the CSV formatted compressed meter data. | ||
*/ | ||
|
||
function convertToCSV(items) { | ||
let csvOutput = 'id:,readings:,timestamp:\n'; | ||
items.forEach(set => { | ||
const data = set.exportVals; | ||
const id = set.id; | ||
data.forEach(reading => { | ||
const info = reading.y; | ||
const timeStamp = moment(reading.x).format('dddd MMM DD YYYY hh:mm a'); | ||
csvOutput += `${id},${info} kwh, ${timeStamp} \n`; | ||
}); | ||
}); | ||
return csvOutput; | ||
} | ||
/** | ||
* Function to download the formatted CSV file to the users computer. | ||
* @param inputCSV A String containing the formatted CSV data. | ||
*/ | ||
function downloadCSV(inputCSV) { | ||
const csvContent = `data:text/csv;charset=utf-8,${inputCSV}`; | ||
const encodedUri = encodeURI(csvContent); | ||
const link = document.createElement('a'); | ||
const fileName = 'exportedDataOED.csv'; | ||
link.setAttribute('href', encodedUri); | ||
link.setAttribute('download', fileName); | ||
document.body.appendChild(link); | ||
|
||
link.click(); // This will download the data file | ||
} | ||
/** | ||
* Function to export compressed data from the graph currently displaying. May be used for routing if more export options are added | ||
* @param dataSets An Object. The compressed data from each meter currently selected in the graph. | ||
*/ | ||
export default function graphExport(dataSets) { | ||
const dataToExport = convertToCSV(dataSets); | ||
downloadCSV(dataToExport); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,9 +14,24 @@ import { fetchMetersDataIfNeeded } from '../actions/meters'; | |
*/ | ||
function mapStateToProps(state) { | ||
const sortedMeters = _.sortBy(_.values(state.meters.byMeterID).map(meter => ({ id: meter.id, name: meter.name.trim() })), 'name'); | ||
|
||
const timeInterval = state.graph.timeInterval; | ||
const data = { datasets: [] }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a fan of the ambiguous naming here. It's hard to figure out what part of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
for (const meterID of state.graph.selectedMeters) { | ||
const readingsData = state.readings.byMeterID[meterID][timeInterval]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As of right now, this is completely correct. However, when the bar chart is added, readings will be retrieved from state.[line OR bar].readings... |
||
if (readingsData !== undefined && !readingsData.isFetching) { | ||
data.datasets.push({ | ||
label: state.meters.byMeterID[meterID].name, | ||
id: state.meters.byMeterID[meterID].id, | ||
timestamp: state.readings.byMeterID[meterID][timeInterval].start_timestamp, | ||
exportVals: state.readings.byMeterID[meterID][timeInterval].readings.map(arr => ({ x: arr[0], y: arr[1] })) | ||
}); | ||
} | ||
} | ||
return { | ||
meters: sortedMeters, | ||
selectedMeters: state.graph.selectedMeters | ||
selectedMeters: state.graph.selectedMeters, | ||
exportVals: data | ||
}; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,23 +10,23 @@ const Meter = require('./../models/Meter'); | |
async function readMetasysData(filePath) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for cleaning this up a bit while you were doing other things. It slipped through linting somehow. I see there are a few other linting errors in here, but they aren't your code so it's no big deal. |
||
const readingArr = []; | ||
let i = 1; | ||
//getting filename | ||
const fileNameArray = filePath.split("/"); | ||
// getting filename | ||
const fileNameArray = filePath.split('/'); | ||
const fileName = fileNameArray.pop(); | ||
//list of readings | ||
// list of readings | ||
const rows = await readCsv(filePath); | ||
//meterInformation | ||
// meterInformation | ||
const meter = await Meter.getByName(fileName.replace('.csv', '')); | ||
|
||
for (const row of rows) { | ||
//timestamp. end time stamp | ||
// timestamp. end time stamp | ||
const timestamp = row[0].toLocaleString(); | ||
const start_timestamp = new Date(timestamp); | ||
let end_timestamp = new Date(timestamp); | ||
end_timestamp.setHours(end_timestamp.getHours()+1); | ||
const end_timestamp = new Date(timestamp); | ||
end_timestamp.setHours(end_timestamp.getHours() + 1); | ||
|
||
|
||
//meterReading | ||
// meterReading | ||
let meterReading = row[3]; | ||
meterReading = meterReading.replace('kWh', ''); | ||
meterReading = parseInt(meterReading); | ||
|
@@ -41,7 +41,7 @@ async function readMetasysData(filePath) { | |
i++; | ||
} | ||
try { | ||
//inserting all the data from an array into database and catching error when it occurs. | ||
// inserting all the data from an array into database and catching error when it occurs. | ||
Reading.insertAll(readingArr); | ||
} catch (err) { | ||
console.error(err); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really not a fan of putting this logic in
UIOptionsComponent
. It's a discrete piece of functionality that only depends on redux state, so I think you should extract it to its own component and include that inUIOptionsComponent
.UIOptionsComponent
is really getting to be a god object that violates single responsibility principle and we should try to fight that hard. I think the entire thing should be refactored, but that's a matter for a different pull request.