Skip to content

Commit

Permalink
Add utilities to combine csvs into one excel workbook
Browse files Browse the repository at this point in the history
  • Loading branch information
erssebaggala committed Oct 6, 2019
1 parent 4b173b3 commit 3093b69
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 9 deletions.
11 changes: 11 additions & 0 deletions background/background-process.html
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,17 @@ <h1>Background process</h1>
log.error(err)
sendLogToUI(task,'error', "Error occured while clearing the baseline reference. Check logs for details.");
}

//
try{
if(task === 'combine_csv_to_excel'){
const result = await utils.combinedCSVsIntoExcel(options.csvDirectory);
sendLogToUI(task, result.status, result.message);
}
}catch(err){
log.error(err)
sendLogToUI(task,'error', "Error occured while combining csv files. Check logs for details.");
}
}


Expand Down
13 changes: 13 additions & 0 deletions background/background-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const bgUtils = window.require('./bg-utils');
const { VENDOR_CM_FORMATS, VENDOR_PM_FORMATS, VENDOR_FM_FORMATS,
VENDOR_CM_PARSERS, VENDOR_PM_PARSERS, VENDOR_FM_PARSERS } = window.require('./vendor-formats');
const tems = window.require('./tems');
const csvToExcelCombiner = window.require('./csv-to-excel-combiner');

//Fix PATH env variable on Mac OSX
if(process.platform === 'darwin'){
Expand Down Expand Up @@ -1575,6 +1576,18 @@ async function clearBaselineReference(){
}
}

async function combinedCSVsIntoExcel(csvDirectory){
try{
const combinedExcelFile = path.join(app.getPath('downloads'), 'combined_csv.xlsx');
await csvToExcelCombiner.combine(csvDirectory, combinedExcelFile);
return {status: 'success', message: combinedExcelFile };
}catch(e){
log.error(e);
return {status: 'error', message: `Error occured while combining csv files. Check logs for details.`};
}
}

exports.combinedCSVsIntoExcel = combinedCSVsIntoExcel;
exports.clearBaselineReference = clearBaselineReference;
exports.importGISFile = importGISFile;
exports.addParamToBaselineRef = addParamToBaselineRef;
Expand Down
58 changes: 58 additions & 0 deletions background/csv-to-excel-combiner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const csv = window.require('csvtojson');
const Excel = window.require('exceljs');


/*
* Combine csv files in a folder
*
* @param string csvFolder
*/
async function combine(csvFolder, combineExcelFile){
files = fs.readdirSync(csvFolder, { withFileTypes: true }).filter(dirent => !dirent.isDirectory()).map(dirent => dirent.name);

var excelOptions = {
filename: combineExcelFile
};

//const workbook = new Excel.Workbook();
var workbook = new Excel.stream.xlsx.WorkbookWriter(excelOptions);

workbook.creator = 'Bodastage Solutions';

for(let i=0; i< files.length; i++) {
const fileName = files[i];
const filePath = path.join(csvFolder, files[i]);
const sheetName = fileName.replace(".csv", "");

const worksheet = workbook.addWorksheet(sheetName);

await new Promise((resolve, reject) => {
try{
csv({noheader:true, output: "csv"})
.fromFile(filePath)
.subscribe( (csvRow)=>{
worksheet.addRow(csvRow).commit();

},(err) => {//onError
log.error(`CSVToExcelCombiner.csvJoJson.onError: ${err.toString()}`);
reject();
},
()=>{//onComplete
resolve(undefined);
});
}catch(e){
log.error(e);
}

});

await worksheet.commit();

}//eo-for

await workbook.commit();
//const res = await workbook.xlsx.writeFile(combineExcelFile);

}

exports.combine = combine;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Boda-Lite",
"version": "0.3.0-beta.4",
"version": "0.3.0-rc.1",
"description": "Boda-Lite is a telecommunication network management application",
"private": true,
"homepage": "./",
Expand Down
5 changes: 3 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import { faLock, faAt, faSpinner, faHome, faPlug, faCog, faDownload,
faFolder, faFile, faStar, faChevronRight, faDotCircle, faFolderOpen,
faLink, faClock, faRss, faChartLine, faSquare, faTable, faInfoCircle
,faAsterisk, faFileAlt,faFrown,faDatabase, faFileExcel, faFileCsv,
faBroadcastTower, faPencilRuler, faBook,faCloudUploadAlt
faBroadcastTower, faPencilRuler, faBook,faCloudUploadAlt,faTools,
faCandyCane
} from '@fortawesome/free-solid-svg-icons'

library.add(faLock, faAt, faSpinner, faHome, faPlug, faCog, faDownload,
Expand All @@ -37,7 +38,7 @@ faChartArea, faBrain, faGem, faUserMd, faGlobeAfrica, faPeopleCarry,
faFolder, faFile, faStar, faChevronRight, faDotCircle, faFolderOpen,
faLink, faClock, faRss, faChartLine, faSquare, faTable, faInfoCircle,
faAsterisk, faFileAlt,faFrown, faDatabase, faFileExcel, faFileCsv,
faBroadcastTower, faPencilRuler, faBook, faCloudUploadAlt);
faBroadcastTower, faPencilRuler, faBook, faCloudUploadAlt, faTools, faCandyCane);

const store = configureStore();

Expand Down
34 changes: 34 additions & 0 deletions src/modules/dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,40 @@ class Dashboard extends React.Component {
</div>

</fieldset>


<fieldset className="col-md-12 fieldset">
<legend className="legend">General</legend>

<div className="row dashboard-icon">

<div className="col-md-2">
<div className="icon-display">
<a
title="Utilties"
href="#/utilities"
onClick={this.setSidePanel('UtilitiesSidePanel')}>
<FontAwesomeIcon icon="tools"/>
</a></div>
<div className="icon-label">Utilties</div>
</div>

<div className="col-md-2">

</div>

<div className="col-md-2">

</div>

<div className="col-md-2">

</div>

<div className="col-md-2">
</div>
</div>
</fieldset>

<fieldset className="col-md-12 fieldset">
<legend className="legend">System</legend>
Expand Down
6 changes: 3 additions & 3 deletions src/modules/gis/gis-reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ const initialState = {

//Radius of the sectors
sectorRadius: {
'gsm': 700,
'umts':500,
'lte': 250,
'gsm': 300,
'umts':200,
'lte': 100,
}
};

Expand Down
4 changes: 3 additions & 1 deletion src/modules/layout/SidePanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import ReportsTree from '../reports/ReportsTree';
import GISLeftPanel from '../gis/GISLeftPanel';
import { connect } from 'react-redux';
import './sidepanel.css'
import UtilitiesSidePanel from '../utilities/UtilitiesSidePanel';

const SidePanels = {
"DashboardSidePanel": DashboardSidePanel,
"ReportsTree": ReportsTree,
"GISLeftPanel": GISLeftPanel
"GISLeftPanel": GISLeftPanel,
"UtilitiesSidePanel": UtilitiesSidePanel
};

class SidePanel extends React.Component{
Expand Down
4 changes: 3 additions & 1 deletion src/modules/layout/Tabs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import CreateCompositeReport from '../reports/CreateCompositeReport';
import GISMap from '../gis/GISMap';
import Baseline from '../baseline/Baseline';
import ParameterLibrary from '../telecomlib/ParameterLibrary';
import CSVToExcelCombiner from '../utilities/CSVToExcelCombiner';

const Components = {
"Help": Help,
Expand All @@ -29,7 +30,8 @@ const Components = {
"CreateCompositeReport": CreateCompositeReport,
"GISMap": GISMap,
"Baseline": Baseline,
"ParameterLibrary": ParameterLibrary
"ParameterLibrary": ParameterLibrary,
"CSVToExcelCombiner": CSVToExcelCombiner
};

class Tabs extends React.Component {
Expand Down
156 changes: 156 additions & 0 deletions src/modules/utilities/CSVToExcelCombiner.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
FileInput,
Button ,
Classes,
ProgressBar,
Intent,

} from "@blueprintjs/core";
import './utilities.css';

const { app, shell } = window.require('electron').remote;
const { ipcRenderer} = window.require("electron")
const fs = window.require('fs');
const log = window.require('electron-log');

export default class CSVToExcelCombiner extends React.Component {

static icon = "candy-cane";
static label = "CSV to Excel Combiner"

constructor(props){
super(props);

this.state = {
inputFolder: "Choose folder...",
processing: false,
notice: null
};

this.combinerListener = null;
}

showFiles = () => {
if (!fs.existsSync(this.state.inputFolder)) {
this.setState({errorMessage: `${this.state.inputFolder} does not exist`})
return;
}
shell.openItem(this.state.inputFolder)
}

/**
* Update the input folder state when the text field value changes
*/
onInputFileChange = (e) => {
this.setState({inputFolder: e.target.files[0].path})
}

combineCSVFiles = () => {
//Confirm that the input folder exists
if( !fs.existsSync(this.state.inputFolder)){
log.info(`Input folder: ${this.state.inputFolder} does not exist`);
this.setState(
{
notice: {
type: 'danger',
message: `Input folder: ${this.state.inputFolder} does not exist`
},
processing: false
}
);
return;
}

let payload = {
csvDirectory: this.state.inputFolder
}

//Set processing to true
this.setState({processing: true });

ipcRenderer.send('parse-cm-request', 'combine_csv_to_excel', JSON.stringify(payload));

this.combinerListener = (event, task, args) => {
const obj = JSON.parse(args)
if(task !== 'combine_csv_to_excel') return;

//error
if(obj.status === 'error' && task === 'combine_csv_to_excel' ){
this.setState({
notice: {type: 'danger', message: obj.message},
processing: false
});
ipcRenderer.removeListener("parse-cm-request", this.combinerListener);
}

//info
if(obj.status === 'info' && task === 'combine_csv_to_excel' ){
this.setNotice('info', obj.message)
}

if(obj.status === "success" && task === 'combine_csv_to_excel' ){
this.setState({
notice: {
type: 'success',
message: ` Combined file generated at: ${obj.message}`
},
processing: false
});

shell.showItemInFolder(obj.message);
ipcRenderer.removeListener("parse-cm-request", this.combinerListener);
}

}
ipcRenderer.on('parse-cm-request', this.combinerListener);


}
render(){
let inputFolderEllipsis = this.state.inputFolder === 'Choose folder...' ? "" : "file-text-dir-rtl";

let notice = null;
if(this.state.notice !== null ){
notice = (<div className={`alert alert-${this.state.notice.type} p-2`} role="alert">{this.state.notice.message}
<button type="button" className="close" aria-label="Close" onClick={this.dismissNotice}>
<span aria-hidden="true">&times;</span>
</button>
</div>)
}

return (
<div>

<fieldset className="col-md-12 fieldset">
<legend className="legend"><FontAwesomeIcon icon="candy-cane"/> CSV to Excel Combiner</legend>

{ this.state.processing ? (<ProgressBar intent={Intent.PRIMARY} className="mt-1 mb-2"/>) : ""}

{notice}

<div className="card-body">
<form>

<div className="form-group row">
<label htmlFor="input_folder" className="col-sm-2 col-form-label">Input folder</label>
<div className="col-sm-8">
<FileInput className={"form-control " + inputFolderEllipsis} text={this.state.inputFolder} onInputChange={this.onInputFileChange} inputProps={{webkitdirectory:"", mozdirectory:"", odirectory:"", directory:"", msdirectory:""}} disabled={this.state.processing}/>
</div>
<div className="col-sm-2">
<Button icon="folder-open" text="" minimal={true} onClick={(e) => this.showFiles(this.state.inputFolder)} disabled={this.state.processing}/>
</div>
</div>

</form>

</div>


<Button icon="play" text="Combine" className={Classes.INTENT_PRIMARY} onClick={this.combineCSVFiles} disabled={this.state.processing}/> &nbsp;
</fieldset>
</div>
);
}
}
Loading

0 comments on commit 3093b69

Please sign in to comment.