diff --git a/src/components/dialog/import-simulator.js b/src/components/dialog/import-simulator.js deleted file mode 100644 index 996c323..0000000 --- a/src/components/dialog/import-simulator.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * File: import-simulator.js - * Author: Markus Grigull - * Date: 04.04.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, PropTypes } from 'react'; -import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap'; - -import Dialog from './dialog'; - -class ImportSimulatorDialog extends Component { - static propTypes = { - show: PropTypes.bool.isRequired, - onClose: PropTypes.func.isRequired - }; - - valid: false; - - constructor(props) { - super(props); - - this.state = { - name: '', - endpoint: '' - }; - } - - onClose(canceled) { - if (canceled === false) { - this.props.onClose(this.state); - } else { - this.props.onClose(); - } - } - - handleChange(e) { - this.setState({ [e.target.id]: e.target.value }); - } - - resetState() { - this.setState({ - name: this.props.simulator.name, - endpoint: this.props.simulator.endpoint - }); - - // validate incoming state - var endpoint = true; - var name = true; - - if (this.props.simulator.name === '') { - name = false; - } - - if (this.props.simulator.endpoint === '') { - endpoint = false; - } - - this.valid = endpoint && name; - } - - validateForm(target) { - // check all controls - var endpoint = true; - var name = true; - - if (this.state.name === '') { - name = false; - } - - if (this.state.endpoint === '') { - endpoint = false; - } - - this.valid = endpoint && name; - - // return state to control - if (target === 'name') return name ? "success" : "error"; - else return endpoint ? "success" : "error"; - } - - render() { - return ( - this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}> -
- - Name - this.handleChange(e)} /> - - - - Endpoint - this.handleChange(e)} /> - - -
-
- ); - } -} - -export default ImportSimulatorDialog; diff --git a/src/components/dialog/import-visualization.js b/src/components/dialog/import-visualization.js new file mode 100644 index 0000000..7ed8113 --- /dev/null +++ b/src/components/dialog/import-visualization.js @@ -0,0 +1,133 @@ +/** + * File: import-simulator.js + * Author: Markus Grigull + * Date: 04.04.2017 + * + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React from 'react'; +import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap'; + +import Dialog from './dialog'; + +class ImportVisualizationDialog extends React.Component { + valid = false; + imported = false; + + constructor(props) { + super(props); + + this.state = { + name: '', + widgets: [], + grid: 0 + }; + } + + onClose(canceled) { + if (canceled === false) { + this.props.onClose(this.state); + } else { + this.props.onClose(); + } + } + + handleChange(e, index) { + this.setState({ [e.target.id]: e.target.value }); + } + + resetState() { + this.setState({ name: '', widgets: [], grid: 0 }); + + this.imported = false; + } + + loadFile(fileList) { + // get file + const file = fileList[0]; + if (!file.type.match('application/json')) { + return; + } + + // create file reader + var reader = new FileReader(); + var self = this; + + reader.onload = function(event) { + // read simulator + const visualization = JSON.parse(event.target.result); + + let defaultSimulator = ""; + if (self.props.simulation.models != null) { + defaultSimulator = self.props.simulation.models[0].simulator; + } + + visualization.widgets.forEach(widget => { + switch (widget.type) { + case 'Value': + case 'Plot': + case 'Table': + case 'PlotTable': + case 'Gauge': + widget.simulator = defaultSimulator; + break; + } + }); + + self.imported = true; + self.valid = true; + self.setState({ name: visualization.name, widgets: visualization.widgets, grid: visualization.grid }); + }; + + reader.readAsText(file); + } + + validateForm(target) { + // check all controls + let name = true; + + if (this.state.name === '') { + name = false; + } + + this.valid = name; + + // return state to control + if (target === 'name') return name ? "success" : "error"; + } + + render() { + return ( + this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}> +
+ + Visualization File + this.loadFile(e.target.files)} /> + + + + Name + this.handleChange(e)} /> + + +
+
+ ); + } +} + +export default ImportVisualizationDialog; diff --git a/src/containers/project.js b/src/containers/project.js index 3e00079..df39dce 100644 --- a/src/containers/project.js +++ b/src/containers/project.js @@ -22,98 +22,80 @@ import React, { Component } from 'react'; import { Container } from 'flux/utils'; import { Button, Modal, Glyphicon } from 'react-bootstrap'; +import FileSaver from 'file-saver'; import AppDispatcher from '../app-dispatcher'; import ProjectStore from '../stores/project-store'; import UserStore from '../stores/user-store'; import VisualizationStore from '../stores/visualization-store'; +import SimulationStore from '../stores/simulation-store'; import CustomTable from '../components/table'; import TableColumn from '../components/table-column'; import NewVisualzationDialog from '../components/dialog/new-visualization'; import EditVisualizationDialog from '../components/dialog/edit-visualization'; +import ImportVisualizationDialog from '../components/dialog/import-visualization'; class Visualizations extends Component { static getStores() { - return [ ProjectStore, VisualizationStore, UserStore ]; + return [ ProjectStore, VisualizationStore, UserStore, SimulationStore ]; } static calculateState(prevState, props) { + prevState = prevState || {}; - let currentProjects = ProjectStore.getState(); - let currentVisualizations = VisualizationStore.getState(); - let sessionToken = UserStore.getState().token; + // load project + const sessionToken = UserStore.getState().token; - if (prevState) { - var projectUpdate = prevState.project; + let project = ProjectStore.getState().find(project => project._id === props.match.params.project); + if (project == null) { + AppDispatcher.dispatch({ + type: 'projects/start-load', + data: props.match.params.project, + token: sessionToken + }); - // Compare content of the visualizations array, reload projects if changed - if (JSON.stringify(prevState.visualizations) !== JSON.stringify(currentVisualizations)) { - Visualizations.loadProjects(sessionToken); - } - - // Compare content of the projects array, update visualizations if changed - if (JSON.stringify(prevState.projects) !== JSON.stringify(currentProjects)) { - projectUpdate = Visualizations.findProjectInState(currentProjects, props.match.params.project); - Visualizations.loadVisualizations(projectUpdate.visualizations, sessionToken); - } - - return { - projects: currentProjects, - visualizations: currentVisualizations, - sessionToken, - - newModal: prevState.newModal, - deleteModal: prevState.deleteModal, - editModal: prevState.editModal, - modalData: prevState.modalData, - - project: projectUpdate - }; - } else { - - let initialProject = Visualizations.findProjectInState(currentProjects, props.match.params.project); - // If projects have been loaded already but visualizations not (redirect from Projects page) - if (initialProject && (!currentVisualizations || currentVisualizations.length === 0)) { - Visualizations.loadVisualizations(initialProject.visualizations, sessionToken); - } - - return { - projects: currentProjects, - visualizations: currentVisualizations, - sessionToken, - - newModal: false, - deleteModal: false, - editModal: false, - modalData: {}, - - project: initialProject || {} - }; + project = {}; } + + // load simulation + let simulation = {}; + + if (project.simulation != null) { + simulation = SimulationStore.getState().find(simulation => simulation._id === project.simulation); + } + + // load visualizations + let visualizations = []; + + if (project.visualizations != null) { + visualizations = VisualizationStore.getState().filter(visualization => project.visualizations.includes(visualization._id)); + } + + return { + visualizations, + project, + simulation, + sessionToken, + + newModal: prevState.newModal || false, + deleteModal: prevState.deleteModal || false, + editModal: prevState.editModal || false, + importModal: prevState.importModal || false, + modalData: prevState.modalData || {} + }; } - static findProjectInState(projects, projectId) { - return projects.find((project) => project._id === projectId); - } - - static loadProjects(token) { - AppDispatcher.dispatch({ - type: 'projects/start-load', - token - }); - } - - static loadVisualizations(visualizations, token) { + componentDidMount() { AppDispatcher.dispatch({ type: 'visualizations/start-load', - data: visualizations, - token + token: this.state.sessionToken }); - } - componentWillMount() { - Visualizations.loadProjects(this.state.sessionToken); + AppDispatcher.dispatch({ + type: 'simulations/start-load', + token: this.state.sessionToken + }); } closeNewModal(data) { @@ -153,6 +135,44 @@ class Visualizations extends Component { } } + closeImportModal(data) { + this.setState({ importModal: false }); + + if (data) { + data.project = this.state.project._id; + + AppDispatcher.dispatch({ + type: 'visualizations/start-add', + data, + token: this.state.sessionToken + }); + + this.setState({ project: {} }, () => { + AppDispatcher.dispatch({ + type: 'projects/start-load', + data: this.props.match.params.project, + token: this.state.sessionToken + }); + }); + } + } + + exportVisualization(index) { + // filter properties + let visualization = Object.assign({}, this.state.visualizations[index]); + delete visualization._id; + delete visualization.project; + delete visualization.user; + + visualization.widgets.forEach(widget => { + delete widget.simulator; + }); + + // show save dialog + const blob = new Blob([JSON.stringify(visualization, null, 2)], { type: 'application/json' }); + FileSaver.saveAs(blob, 'visualization - ' + visualization.name + '.json'); + } + onModalKeyPress = (event) => { if (event.key === 'Enter') { event.preventDefault(); @@ -162,30 +182,29 @@ class Visualizations extends Component { } render() { - // get visualizations for this project - var visualizations = []; - if (this.state.visualizations && this.state.project.visualizations) { - visualizations = this.state.visualizations.filter( - (visualization) => this.state.project.visualizations.includes(visualization._id) - ).sort( - (visA, visB) => visA.name.localeCompare(visB.name) - ); - } - return (

{this.state.project.name}

- + - this.setState({ editModal: true, modalData: visualizations[index] })} onDelete={(index) => this.setState({ deleteModal: true, modalData: visualizations[index] })} /> + this.setState({ editModal: true, modalData: this.state.visualizations[index] })} + onDelete={(index) => this.setState({ deleteModal: true, modalData: this.state.visualizations[index] })} + onExport={index => this.exportVisualization(index)} + /> + this.closeNewModal(data)} /> - this.closeEditModal(data)} visualization={this.state.modalData} /> + this.closeImportModal(data)} simulation={this.state.simulation} /> this.setState({ deleteModal: false })} onKeyPress={this.onModalKeyPress}> diff --git a/src/containers/simulation.js b/src/containers/simulation.js index e28a8e9..6d28515 100644 --- a/src/containers/simulation.js +++ b/src/containers/simulation.js @@ -173,42 +173,6 @@ class Simulation extends React.Component { } } - exportSimulationModel(data) { - // filter properties - var model = Object.assign({}, data); - - // get simulator name - this.state.simulators.forEach(simulator => { - if (simulator._id === model.simulator) { - model.simulator = simulator.name; - } - }); - - // show save dialog - const blob = new Blob([JSON.stringify(model, null, 2)], { type: 'application/json' }); - FileSaver.saveAs(blob, model.name + '.json'); - } - - loadFile(fileList) { - // get file - const file = fileList[0]; - if (!file.type.match('application/json')) { - return; - } - - // create file reader - var reader = new FileReader(); - var self = this; - - reader.onload = function(event) { - // read simulation model - const simulationModel = JSON.parse(event.target.result); - self.setState({ importModal: true, modalData: simulationModel }); - }; - - reader.readAsText(file); - } - render() { return (
diff --git a/src/containers/simulations.js b/src/containers/simulations.js index 3acc22a..1f9da4c 100644 --- a/src/containers/simulations.js +++ b/src/containers/simulations.js @@ -141,26 +141,6 @@ class Simulations extends Component { } } - loadFile(fileList) { - // get file - const file = fileList[0]; - if (!file.type.match('application/json')) { - return; - } - - // create file reader - var reader = new FileReader(); - var self = this; - - reader.onload = function(event) { - // read simulation - const simulation = JSON.parse(event.target.result); - self.setState({ importModal: true, modalSimulation: simulation }); - }; - - reader.readAsText(file); - } - exportSimulation(index) { // filter properties let simulation = Object.assign({}, this.state.simulations[index]);