diff --git a/src/api/rest-api.js b/src/api/rest-api.js index e81ffa4..2709d05 100644 --- a/src/api/rest-api.js +++ b/src/api/rest-api.js @@ -82,6 +82,24 @@ class RestAPI { }); }); } + + upload(url, data, token) { + return new Promise(function (resolve, reject) { + var req = request.post(url).send(data); + + if (token != null) { + req.set('x-access-token', token); + } + + req.end(function (error, res) { + if (res == null || res.status !== 200) { + reject(error); + } else { + resolve(JSON.parse(res.text)); + } + }); + }); + } } export default new RestAPI(); diff --git a/src/components/dialog/edit-widget-image.js b/src/components/dialog/edit-widget-image.js new file mode 100644 index 0000000..f7b06e4 --- /dev/null +++ b/src/components/dialog/edit-widget-image.js @@ -0,0 +1,71 @@ +/** + * File: edit-widget-value.js + * Author: Markus Grigull + * Date: 04.03.2017 + * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + **********************************************************************************/ + +import React, { Component } from 'react'; +import { FormGroup, FormControl, ControlLabel, Button } from 'react-bootstrap'; + +import AppDispatcher from '../../app-dispatcher'; + +class EditImageWidget extends Component { + constructor(props) { + super(props); + + this.state = { + widget: { + file: '' + }, + fileList: null + }; + } + + componentWillReceiveProps(nextProps) { + this.setState({ widget: nextProps.widget }); + } + + startFileUpload() { + // get selected file + var formData = new FormData(); + + for (var key in this.state.fileList) { + if (this.state.fileList.hasOwnProperty(key) && this.state.fileList[key] instanceof File) { + formData.append(key, this.state.fileList[key]); + } + } + + // upload files + AppDispatcher.dispatch({ + type: 'files/start-upload', + data: formData + }); + } + + render() { + return ( +
+ + Image + this.props.handleChange(e)}> + {this.props.files.map((file, index) => ( + + ))} + + + + + Upload + this.setState({ fileList: e.target.files }) } /> + + + +
+ ); + } +} + +export default EditImageWidget; diff --git a/src/components/dialog/edit-widget.js b/src/components/dialog/edit-widget.js index 8a7c3b0..506fef3 100644 --- a/src/components/dialog/edit-widget.js +++ b/src/components/dialog/edit-widget.js @@ -83,13 +83,13 @@ class EditWidgetDialog extends Component { } else if (this.props.widget.type === 'Table') { widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />; } else if (this.props.widget.type === 'Image') { - widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />; + widgetDialog = this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />; } } return ( this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}> -
+ Name this.handleChange(e)} /> diff --git a/src/components/widget-image.js b/src/components/widget-image.js new file mode 100644 index 0000000..c04a4a1 --- /dev/null +++ b/src/components/widget-image.js @@ -0,0 +1,49 @@ +/** + * File: widget-image.js + * Author: Markus Grigull + * Date: 14.03.2017 + * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + **********************************************************************************/ + +import React, { Component } from 'react'; + +const API_URL = 'http://localhost:4000/'; + +class WidgetImage extends Component { + constructor(props) { + super(props); + + this.state = { + file: null + }; + } + + componentWillReceiveProps(nextProps) { + // check if file is set + if (nextProps.widget.file == null) { + this.setState({ file: null }); + return; + } + + // get file by id + nextProps.files.forEach(file => { + if (file._id === nextProps.widget.file) { + this.setState({ file: file }); + } + }); + } + + render() { + return ( +
+ {this.state.file && + {this.state.file.name} + } +
+ ); + } +} + +export default WidgetImage; diff --git a/src/containers/visualization.js b/src/containers/visualization.js index ac4ff03..b4228b1 100644 --- a/src/containers/visualization.js +++ b/src/containers/visualization.js @@ -20,11 +20,12 @@ import EditWidget from '../components/dialog/edit-widget'; import VisualizationStore from '../stores/visualization-store'; import ProjectStore from '../stores/project-store'; import SimulationStore from '../stores/simulation-store'; +import FileStore from '../stores/file-store'; import AppDispatcher from '../app-dispatcher'; class Visualization extends Component { static getStores() { - return [ VisualizationStore, ProjectStore, SimulationStore ]; + return [ VisualizationStore, ProjectStore, SimulationStore, FileStore ]; } static calculateState(prevState) { @@ -36,6 +37,7 @@ class Visualization extends Component { visualizations: VisualizationStore.getState(), projects: ProjectStore.getState(), simulations: SimulationStore.getState(), + files: FileStore.getState(), visualization: prevState.visualization || {}, project: prevState.project || null, @@ -132,6 +134,9 @@ class Visualization extends Component { widget.width = 500; widget.height = 400; widget.time = 60 + } else if (item.name === 'Image') { + widget.width = 200; + widget.height = 200; } var visualization = this.state.visualization; @@ -280,7 +285,7 @@ class Visualization extends Component { - + } @@ -305,7 +310,7 @@ class Visualization extends Component { ))} - this.closeEdit(data)} widget={this.state.modalData} simulation={this.state.simulation} /> + this.closeEdit(data)} widget={this.state.modalData} simulation={this.state.simulation} files={this.state.files} /> ); diff --git a/src/containers/widget.js b/src/containers/widget.js index dd4dc74..f145d28 100644 --- a/src/containers/widget.js +++ b/src/containers/widget.js @@ -12,37 +12,48 @@ import { Container } from 'flux/utils'; import { ContextMenuTrigger } from 'react-contextmenu'; import Rnd from 'react-rnd'; +import AppDispatcher from '../app-dispatcher'; import SimulatorDataStore from '../stores/simulator-data-store'; +import FileStore from '../stores/file-store'; import WidgetValue from '../components/widget-value'; import WidgetPlot from '../components/widget-plot'; import WidgetTable from '../components/widget-table'; import WidgetLabel from '../components/widget-label'; import WidgetPlotTable from '../components/widget-plot-table'; +import WidgetImage from '../components/widget-image'; import '../styles/widgets.css'; class Widget extends Component { static getStores() { - return [ SimulatorDataStore ]; + return [ SimulatorDataStore, FileStore ]; } static calculateState(prevState) { if (prevState) { return { simulatorData: SimulatorDataStore.getState(), + files: FileStore.getState(), sequence: prevState.sequence + 1 } } else { return { simulatorData: SimulatorDataStore.getState(), + files: FileStore.getState(), sequence: 0 }; } } + componentWillMount() { + AppDispatcher.dispatch({ + type: 'files/start-load' + }); + } + dragStop(event, ui) { // update widget var widget = this.props.data; @@ -95,6 +106,8 @@ class Widget extends Component { element = } else if (widget.type === 'PlotTable') { element = + } else if (widget.type === 'Image') { + element = } if (this.props.editing) { diff --git a/src/data-managers/files-data-manager.js b/src/data-managers/files-data-manager.js new file mode 100644 index 0000000..385c778 --- /dev/null +++ b/src/data-managers/files-data-manager.js @@ -0,0 +1,35 @@ +/** + * File: files-data-manager.js + * Author: Markus Grigull + * Date: 16.03.2017 + * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + **********************************************************************************/ + +import RestDataManager from './rest-data-manager'; +import RestAPI from '../api/rest-api'; +import AppDispatcher from '../app-dispatcher'; + +class FilesDataManager extends RestDataManager { + constructor() { + super('file', '/files'); + } + + upload(file) { + RestAPI.upload(this.makeURL('/upload'), file).then(response => { + AppDispatcher.dispatch({ + type: 'files/uploaded' + }); + + console.log(response); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'files/upload-error', + error: error + }); + }); + } +} + +export default new FilesDataManager(); diff --git a/src/data-managers/simulators-data-manager.js b/src/data-managers/simulators-data-manager.js index ee6e25c..94c8bac 100644 --- a/src/data-managers/simulators-data-manager.js +++ b/src/data-managers/simulators-data-manager.js @@ -8,5 +8,21 @@ **********************************************************************************/ import RestDataManager from './rest-data-manager'; +import RestAPI from '../api/rest-api'; +//import AppDispatcher from '../app-dispatcher'; -export default new RestDataManager('simulator', '/simulators'); +class SimulatorsDataManager extends RestDataManager { + constructor() { + super('simulator', '/simulators'); + } + + isRunning(simulator) { + RestAPI.get('http://localhost/nodes.json').then(response => { + console.log(response); + }).catch(error => { + console.log(error); + }); + } +} + +export default new SimulatorsDataManager(); diff --git a/src/stores/file-store.js b/src/stores/file-store.js new file mode 100644 index 0000000..57bf1c9 --- /dev/null +++ b/src/stores/file-store.js @@ -0,0 +1,38 @@ +/** + * File: file-store.js + * Author: Markus Grigull + * Date: 16.03.2017 + * Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + **********************************************************************************/ + +import ArrayStore from './array-store'; +import FilesDataManager from '../data-managers/files-data-manager'; + +class FileStore extends ArrayStore { + constructor() { + super('files', FilesDataManager); + } + + reduce(state, action) { + switch (action.type) { + case 'files/start-upload': + FilesDataManager.upload(action.data); + return state; + + case 'files/uploaded': + console.log('ready uploaded'); + return state; + + case 'files/upload-error': + console.log(action.error); + return state; + + default: + return super.reduce(state, action); + } + } +} + +export default new FileStore(); diff --git a/src/stores/simulator-store.js b/src/stores/simulator-store.js index 9413db7..5b9fde4 100644 --- a/src/stores/simulator-store.js +++ b/src/stores/simulator-store.js @@ -10,4 +10,31 @@ import ArrayStore from './array-store'; import SimulatorsDataManager from '../data-managers/simulators-data-manager'; -export default new ArrayStore('simulators', SimulatorsDataManager); +class SimulatorStore extends ArrayStore { + constructor() { + super('simulators', SimulatorsDataManager); + } + + reduce(state, action) { + // handle action + state = super.reduce(state, action); + + if (action.type === 'simulators/loaded') { + // get simulator running state + if (Array.isArray(action.data)) { + action.data.forEach((simulator) => { + //SimulatorsDataManager.isRunning(simulator); + }); + } else { + //SimulatorsDataManager.isRunning(action.data); + } + } else if (action.type === 'simulators/running') { + // set running state + console.log(action); + } + + return state; + } +} + +export default new SimulatorStore();