From 78a604af2ec560b0349212314fa306a3fedbcf76 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 20 Aug 2019 11:47:23 +0200 Subject: [PATCH] started creation of scenario element to replace simulation and project, WIP --- src/components/dialogs/edit-scenario.js | 99 ++++++ src/components/dialogs/import-scenario.js | 151 +++++++++ src/components/dialogs/new-scenario.js | 95 ++++++ src/components/menu-sidebar.js | 6 +- src/containers/app.js | 32 +- src/containers/scenario.js | 297 ++++++++++++++++++ src/containers/scenarios.js | 328 ++++++++++++++++++++ src/containers/simulation-model.js | 12 +- src/data-managers/scenarios-data-manager.js | 60 ++++ src/stores/scenario-store.js | 63 ++++ 10 files changed, 1122 insertions(+), 21 deletions(-) create mode 100644 src/components/dialogs/edit-scenario.js create mode 100644 src/components/dialogs/import-scenario.js create mode 100644 src/components/dialogs/new-scenario.js create mode 100644 src/containers/scenario.js create mode 100644 src/containers/scenarios.js create mode 100644 src/data-managers/scenarios-data-manager.js create mode 100644 src/stores/scenario-store.js diff --git a/src/components/dialogs/edit-scenario.js b/src/components/dialogs/edit-scenario.js new file mode 100644 index 0000000..0ce5dd6 --- /dev/null +++ b/src/components/dialogs/edit-scenario.js @@ -0,0 +1,99 @@ +/** + * File: edit-scenario.js + * Author: Sonja Happ + * Date: 20.08.2019 + * + * 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, FormLabel, Col} from 'react-bootstrap'; + +import Dialog from './dialog'; +import ParametersEditor from '../parameters-editor'; + +class EditScenarioDialog extends React.Component { + valid = true; + + constructor(props) { + super(props); + + this.state = { + name: '', + id: '', + startParameters: {} + }; + } + + onClose = canceled => { + if (canceled) { + if (this.props.onClose != null) { + this.props.onClose(); + } + + return; + } + + if (this.valid && this.props.onClose != null) { + this.props.onClose(this.state); + } + }; + + handleChange = event => { + this.setState({ [event.target.id]: event.target.value }); + + let name = true; + + if (this.state.name === '') { + name = false; + } + + this.valid = name; + + }; + + resetState = () => { + this.setState({ + name: this.props.scenario.name, + id: this.props.scenario.id, + startParameters: this.props.scenario.startParameters || {} + }); + } + + handleStartParametersChange = startParameters => { + this.setState({ startParameters }); + } + + render() { + return +
+ + Name + + + + + + Start Parameters + + + +
+
; + } +} + +export default EditScenarioDialog; diff --git a/src/components/dialogs/import-scenario.js b/src/components/dialogs/import-scenario.js new file mode 100644 index 0000000..bab9f46 --- /dev/null +++ b/src/components/dialogs/import-scenario.js @@ -0,0 +1,151 @@ +/** + * File: import-scenario.js + * Author: Sonja Happ + * Date: 20.08.2019 + * + * 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, FormLabel, Col} from 'react-bootstrap'; + +import Dialog from './dialog'; +import ParametersEditor from '../parameters-editor'; + +class ImportScenarioDialog extends React.Component { + valid = false; + imported = false; + + constructor(props) { + super(props); + + this.state = { + name: '', + running: '', + simulationModels: [], + startParameters: {} + }; + } + + onClose = canceled => { + if (canceled) { + if (this.props.onClose != null) { + this.props.onClose(); + } + + return; + } + + if (this.valid && this.props.onClose != null) { + this.props.onClose(this.state); + } + } + + handleChange(e, index) { + if (e.target.id === 'simulator') { + const models = this.state.models; + models[index].simulator = JSON.parse(e.target.value); + + this.setState({ models }); + + return; + } + + this.setState({ [e.target.id]: e.target.value }); + + // check all controls + let name = true; + + if (this.state.name === '') { + name = false; + } + + this.valid = name; + } + + resetState = () => { + this.setState({ name: '', models: [], startParameters: {} }); + + this.imported = false; + } + + loadFile = event => { + const file = event.target.files[0]; + + if (!file.type.match('application/json')) { + return; + } + + // create file reader + const reader = new FileReader(); + const self = this; + + reader.onload = onloadEvent => { + const scenario = JSON.parse(onloadEvent.target.result); + + // scenario.simulationModels.forEach(model => { + // model.simulator = { + // node: self.props.nodes[0]._id, + // simulator: 0 + // }; + // }); + + self.imported = true; + self.valid = true; + self.setState({ name: scenario.name, models: scenario.simulationModels, startParameters: scenario.startParameters, running: scenario.running }); + }; + + reader.readAsText(file); + } + + render() { + return +
+ + Scenario File + + + + + Name + this.handleChange(e)} /> + + + + + Start Parameters + + + + + {/* {this.state.models.map((model, index) => ( + + {model.name} - Simulator + this.handleChange(e, index)}> + {this.props.nodes.map(node => ( + node.simulators.map((simulator, index) => ( + + )) + ))} + + + ))} */} +
+
; + } +} + +export default ImportScenarioDialog; diff --git a/src/components/dialogs/new-scenario.js b/src/components/dialogs/new-scenario.js new file mode 100644 index 0000000..ff8dc68 --- /dev/null +++ b/src/components/dialogs/new-scenario.js @@ -0,0 +1,95 @@ +/** + * File: new-scenario.js + * Author: Sonja Happ + * Date: 20.08.2019 + * + * 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, FormLabel, Col} from 'react-bootstrap'; + +import Dialog from './dialog'; +import ParametersEditor from '../parameters-editor'; + +class NewScenarioDialog extends React.Component { + valid = false; + + constructor(props) { + super(props); + + this.state = { + name: '', + startParameters: {}, + running: false + }; + } + + onClose = canceled => { + if (canceled) { + if (this.props.onClose != null) { + this.props.onClose(); + } + + return; + } + + if (this.valid && this.props.onClose != null) { + this.props.onClose(this.state); + } + } + + handleChange = event => { + this.setState({ [event.target.id]: event.target.value }); + + // check all controls + let name = true; + + if (this.state.name === '') { + name = false; + } + + this.valid = name; + } + + resetState = () => { + this.setState({ name: '', startParameters: {} }); + } + + handleStartParametersChange = startParameters => { + this.setState({ startParameters }); + } + + render() { + return +
+ + Name + + + + + + Start Parameters + + + +
+
; + } +} + +export default NewScenarioDialog; diff --git a/src/components/menu-sidebar.js b/src/components/menu-sidebar.js index 000cdf7..70a633a 100644 --- a/src/components/menu-sidebar.js +++ b/src/components/menu-sidebar.js @@ -22,6 +22,9 @@ import React from 'react'; import { NavLink } from 'react-router-dom'; +//
  • Simulations
  • +//
  • Projects
  • + class SidebarMenu extends React.Component { render() { return ( @@ -30,8 +33,7 @@ class SidebarMenu extends React.Component {
    • Home
    • -
    • Projects
    • -
    • Simulations
    • +
    • Scenarios
    • Simulators
    • { this.props.currentRole === 'Admin' ?
    • User Management
    • : '' diff --git a/src/containers/app.js b/src/containers/app.js index 763e012..93c860e 100644 --- a/src/containers/app.js +++ b/src/containers/app.js @@ -29,7 +29,7 @@ import { Col } from 'react-bootstrap'; import { Hidden } from 'react-grid-system' import AppDispatcher from '../app-dispatcher'; -import SimulationStore from '../stores/simulation-store'; +import ScenarioStore from '../stores/scenario-store'; import SimulatorStore from '../stores/simulator-store'; import UserStore from '../stores/user-store'; import NotificationsDataManager from '../data-managers/notifications-data-manager'; @@ -40,12 +40,14 @@ import Footer from '../components/footer'; import SidebarMenu from '../components/menu-sidebar'; import HeaderMenu from '../components/header-menu'; -import Projects from './projects'; -import Project from './project'; +//import Projects from './projects'; +//import Project from './project'; import Simulators from './simulators'; import Visualization from './visualization'; -import Simulations from './simulations'; -import Simulation from './simulation'; +//import Simulations from './simulations'; +//import Simulation from './simulation'; +import Scenarios from './scenarios' +import Scenario from './scenario' import SimulationModel from './simulation-model'; import Users from './users'; @@ -54,7 +56,7 @@ import '../styles/app.css'; class App extends React.Component { static getStores() { - return [ SimulatorStore, UserStore, SimulationStore ]; + return [ SimulatorStore, UserStore, ScenarioStore]; } static calculateState(prevState) { @@ -62,7 +64,7 @@ class App extends React.Component { return { simulators: SimulatorStore.getState(), - simulations: SimulationStore.getState(), + scenarios: ScenarioStore.getState(), currentRole: currentUser ? currentUser.role : '', currentUsername: currentUser ? currentUser.username: '', currentUserID: UserStore.getState().userid, @@ -90,14 +92,14 @@ class App extends React.Component { } componentDidMount() { - // load all simulators and simulations to fetch simulation data + // load all simulators and scenarios to fetch data AppDispatcher.dispatch({ type: 'simulators/start-load', token: this.state.token }); AppDispatcher.dispatch({ - type: 'simulations/start-load', + type: 'scenarios/start-load', token: this.state.token }); @@ -142,11 +144,9 @@ class App extends React.Component {
      - - - - + + @@ -161,6 +161,12 @@ class App extends React.Component { } } +// Removed routes +// +// +// +// + let fluxContainerConverter = require('./FluxContainerConverter'); export default Container.create(fluxContainerConverter.convert(App)); //DragDropContext(HTML5Backend)(Container.create(App)); diff --git a/src/containers/scenario.js b/src/containers/scenario.js new file mode 100644 index 0000000..ae03741 --- /dev/null +++ b/src/containers/scenario.js @@ -0,0 +1,297 @@ +/** + * File: scenario.js + * Author: Sonja Happ + * Date: 20.08.2019 + * + * 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 { Container } from 'flux/utils'; +import { Button } from 'react-bootstrap'; +import FileSaver from 'file-saver'; +import _ from 'lodash'; + +import ScenarioStore from '../stores/scenario-store'; +import SimulatorStore from '../stores/simulator-store'; +import SimulationModelStore from '../stores/simulation-model-store'; +import UserStore from '../stores/user-store'; +import AppDispatcher from '../app-dispatcher'; + +import Icon from '../components/icon'; +import Table from '../components/table'; +import TableColumn from '../components/table-column'; +import ImportSimulationModelDialog from '../components/dialogs/import-simulation-model'; + +import SimulatorAction from '../components/simulator-action'; +import DeleteDialog from '../components/dialogs/delete-dialog'; + +class Scenario extends React.Component { + static getStores() { + return [ ScenarioStore, SimulatorStore, SimulationModelStore, UserStore ]; + } + + static calculateState(prevState, props) { + // get selected scenario + const sessionToken = UserStore.getState().token; + + let scenario = ScenarioStore.getState().find(s => s.id === props.match.params.scenario); + if (scenario == null) { + AppDispatcher.dispatch({ + type: 'scenarios/start-load', + data: props.match.params.scenario, + token: sessionToken + }); + + scenario = {}; + } + + // load models + let simulationModels = []; + if (scenario.simulationModels != null) { + simulationModels = SimulationModelStore.getState().filter(m => m != null && scenario.simulationModels.includes(m.id)); + } + + return { + simulationModels, + scenario, + + //simulators: SimulatorStore.getState(), + sessionToken, + + deleteModal: false, + importModal: false, + modalData: {}, + + selectedSimulationModels: [] + } + } + + componentWillMount() { + AppDispatcher.dispatch({ + type: 'scenarios/start-load', + token: this.state.sessionToken + }); + + AppDispatcher.dispatch({ + type: 'simulationModels/start-load', + token: this.state.sessionToken + }); + + AppDispatcher.dispatch({ + type: 'simulators/start-load', + token: this.state.sessionToken + }); + + //TODO users + + //TODO dashboards + + + + + } + + addSimulationModel = () => { + const simulationModel = { + scenario: this.state.scenario.id, + name: 'New Simulation Model', + simulator: this.state.simulators.length > 0 ? this.state.simulators[0].id : null, + outputLength: 1, + outputMapping: [{ name: 'Signal', type: 'Type' }], + inputLength: 1, + inputMapping: [{ name: 'Signal', type: 'Type' }] + }; + + AppDispatcher.dispatch({ + type: 'simulationModels/start-add', + data: simulationModel, + token: this.state.sessionToken + }); + + this.setState({ scenario: {} }, () => { + AppDispatcher.dispatch({ + type: 'scenarios/start-load', + data: this.props.match.params.scenario, + token: this.state.sessionToken + }); + }); + } + + closeDeleteModal = confirmDelete => { + this.setState({ deleteModal: false }); + + if (confirmDelete === false) { + return; + } + + AppDispatcher.dispatch({ + type: 'simulationModels/start-remove', + data: this.state.modalData, + token: this.state.sessionToken + }); + } + + importSimulationModel = simulationModel => { + this.setState({ importModal: false }); + + if (simulationModel == null) { + return; + } + + simulationModel.scenario = this.state.scenario.id; + + console.log(simulationModel); + + AppDispatcher.dispatch({ + type: 'simulationModels/start-add', + data: simulationModel, + token: this.state.sessionToken + }); + + this.setState({ scenario: {} }, () => { + AppDispatcher.dispatch({ + type: 'scenarios/start-load', + data: this.props.match.params.scenario, + token: this.state.sessionToken + }); + }); + } + + getSimulatorName(simulatorId) { + for (let simulator of this.state.simulators) { + if (simulator.id === simulatorId) { + return _.get(simulator, 'properties.name') || _.get(simulator, 'rawProperties.name') || simulator.uuid; + } + } + } + + exportModel(index) { + // filter properties + const model = Object.assign({}, this.state.simulationModels[index]); + + delete model.simulator; + delete model.scenario; + + // show save dialog + const blob = new Blob([JSON.stringify(model, null, 2)], { type: 'application/json' }); + FileSaver.saveAs(blob, 'simulation model - ' + model.name + '.json'); + } + + onSimulationModelChecked(index, event) { + const selectedSimulationModels = Object.assign([], this.state.selectedSimulationModels); + for (let key in selectedSimulationModels) { + if (selectedSimulationModels[key] === index) { + // update existing entry + if (event.target.checked) { + return; + } + + selectedSimulationModels.splice(key, 1); + + this.setState({ selectedSimulationModels }); + return; + } + } + + // add new entry + if (event.target.checked === false) { + return; + } + + selectedSimulationModels.push(index); + this.setState({ selectedSimulationModels }); + } + + runAction = action => { + for (let index of this.state.selectedSimulationModels) { + // get simulator for model + let simulator = null; + for (let sim of this.state.simulators) { + if (sim._id === this.state.simulationModels[index].simulator) { + simulator = sim; + } + } + + if (simulator == null) { + continue; + } + + if (action.data.action === 'start') { + action.data.parameters = this.state.simulationModels[index].startParameters; + } + + AppDispatcher.dispatch({ + type: 'simulators/start-action', + simulator, + data: action.data, + token: this.state.sessionToken + }); + } + } + + render() { + const buttonStyle = { + marginLeft: '10px' + }; + + return
      +

      {this.state.simulation.name}

      + + + this.onSimulationModelChecked(index, event)} width='30' /> + + this.getSimulatorName(simulator)} /> + + + this.setState({ deleteModal: true, modalData: this.state.simulationModels[index], modalIndex: index })} + onExport={index => this.exportModel(index)} + /> +
      + +
      + +
      + +
      + + +
      + +
      + + + + +
      ; + } +} + +let fluxContainerConverter = require('./FluxContainerConverter'); +export default Container.create(fluxContainerConverter.convert(Scenario), { withProps: true }); diff --git a/src/containers/scenarios.js b/src/containers/scenarios.js new file mode 100644 index 0000000..72b63ee --- /dev/null +++ b/src/containers/scenarios.js @@ -0,0 +1,328 @@ +/** + * File: scenarios.js + * Author: Sonja Happ + * Date: 20.08.2019 + * + * 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, { Component } from 'react'; +import { Container } from 'flux/utils'; +import { Button } from 'react-bootstrap'; +import FileSaver from 'file-saver'; + +import AppDispatcher from '../app-dispatcher'; +import ScenarioStore from '../stores/scenario-store'; +import UserStore from '../stores/user-store'; +import SimulatorStore from '../stores/simulator-store'; +import SimulationModelStore from '../stores/simulation-model-store'; + +import Icon from '../components/icon'; +import Table from '../components/table'; +import TableColumn from '../components/table-column'; +import NewScenarioDialog from '../components/dialogs/new-scenario'; +import EditScenarioDialog from '../components/dialogs/edit-scenario'; +import ImportScenarioDialog from '../components/dialogs/import-scenario'; + +import SimulatorAction from '../components/simulator-action'; +import DeleteDialog from '../components/dialogs/delete-dialog'; + +class Scenarios extends Component { + static getStores() { + return [ ScenarioStore, UserStore, SimulatorStore, SimulationModelStore ]; + } + + static calculateState() { + const scenarios = ScenarioStore.getState(); + const simulationModels = SimulationModelStore.getState(); + const simulators = SimulatorStore.getState(); + + const sessionToken = UserStore.getState().token; + + return { + scenarios, + simulationModels, + simulators, + sessionToken, + + newModal: false, + deleteModal: false, + editModal: false, + importModal: false, + modalScenario: {}, + + selectedScenarios: [] + }; + } + + componentDidMount() { + AppDispatcher.dispatch({ + type: 'scenarios/start-load', + token: this.state.sessionToken + }); + } + + componentDidUpdate() { + const simulationModelIds = []; + const simulatorIds = []; + + for (let scenario of this.state.scenarios) { + for (let modelId of scenario.simulationModels) { + const model = this.state.simulationModels.find(m => m != null && m.id === modelId); + + if (model == null) { + simulationModelIds.push(modelId); + + continue; + } + + if (this.state.simulators.includes(s => s._id === model.simulator) === false) { + simulatorIds.push(model.simulator); + } + } + } + + if (simulationModelIds.length > 0) { + AppDispatcher.dispatch({ + type: 'simulationModels/start-load', + data: simulationModelIds, + token: this.state.sessionToken + }); + } + + if (simulatorIds.length > 0) { + AppDispatcher.dispatch({ + type: 'simulators/start-load', + data: simulatorIds, + token: this.state.sessionToken + }); + } + } + + closeNewModal(data) { + this.setState({ newModal : false }); + + if (data) { + AppDispatcher.dispatch({ + type: 'scenarios/start-add', + data, + token: this.state.sessionToken + }); + } + } + + showDeleteModal(id) { + // get scenario by id + var deleteScenario; + + this.state.scenarios.forEach((scenario) => { + if (scenario.id === id) { + deleteScenario = scenario; + } + }); + + this.setState({ deleteModal: true, modalScenario: deleteScenario }); + } + + closeDeleteModal = confirmDelete => { + this.setState({ deleteModal: false }); + + if (confirmDelete === false) { + return; + } + + AppDispatcher.dispatch({ + type: 'scenarios/start-remove', + data: this.state.modalScenario, + token: this.state.sessionToken + }); + } + + showEditModal(id) { + // get scenario by id + var editScenario; + + this.state.scenarios.forEach((scenario) => { + if (scenario.id === id) { + editScenario = scenario; + } + }); + + this.setState({ editModal: true, modalScenario: editScenario }); + } + + closeEditModal(data) { + this.setState({ editModal : false }); + + if (data != null) { + AppDispatcher.dispatch({ + type: 'scenarios/start-edit', + data, + token: this.state.sessionToken + }); + } + } + + closeImportModal(data) { + this.setState({ importModal: false }); + + if (data) { + AppDispatcher.dispatch({ + type: 'scenarios/start-add', + data, + token: this.state.sessionToken + }); + } + } + + onModalKeyPress = (event) => { + if (event.key === 'Enter') { + event.preventDefault(); + + this.confirmDeleteModal(); + } + } + + exportScenario(index) { + // filter properties + let scenario = Object.assign({}, this.state.scenarios[index]); + delete scenario.id; + delete scenario.users; + delete scenario.dashboards; + + scenario.simulationModels.forEach(model => { + delete model.simulator; + }); + + // show save dialog + const blob = new Blob([JSON.stringify(scenario, null, 2)], { type: 'application/json' }); + FileSaver.saveAs(blob, 'scenario - ' + scenario.name + '.json'); + } + + onScenarioChecked(index, event) { + const selectedScenarios = Object.assign([], this.state.selectedScenarios); + for (let key in selectedScenarios) { + if (selectedScenarios[key] === index) { + // update existing entry + if (event.target.checked) { + return; + } + + selectedScenarios.splice(key, 1); + + this.setState({ selectedScenarios }); + return; + } + } + + // add new entry + if (event.target.checked === false) { + return; + } + + selectedScenarios.push(index); + this.setState({ selectedScenarios }); + } + + runAction = action => { + for (let index of this.state.selectedScenarios) { + for (let model of this.state.scenarios[index].simulationModels) { + // get simulation model + const simulationModel = this.state.simulationModels.find(m => m != null && m.id === model); + if (simulationModel == null) { + continue; + } + + // get simulator for model + let simulator = null; + for (let sim of this.state.simulators) { + if (sim.id === simulationModel.simulatorID) { + simulator = sim; + } + } + + if (simulator == null) { + continue; + } + + if (action.data.action === 'start') { + action.data.parameters = Object.assign({}, this.state.scenarios[index].startParameters, simulationModel.startParameters); + } + + AppDispatcher.dispatch({ + type: 'simulators/start-action', + simulator, + data: action.data, + token: this.state.sessionToken + }); + } + } + } + + render() { + const buttonStyle = { + marginLeft: '10px' + }; + + return ( +
      +

      Scenarios

      + + + this.onScenarioChecked(index, event)} width='30' /> + + this.setState({ editModal: true, modalScenario: this.state.scenarios[index] })} + onDelete={index => this.setState({ deleteModal: true, modalScenario: this.state.scenarios[index] })} + onExport={index => this.exportScenario(index)} + /> +
      + +
      + +
      + +
      + + +
      + +
      + + this.closeNewModal(data)} /> + this.closeEditModal(data)} scenario={this.state.modalScenario} /> + this.closeImportModal(data)} nodes={this.state.nodes} /> + + +
      + ); + } +} + +let fluxContainerConverter = require('./FluxContainerConverter'); +export default Container.create(fluxContainerConverter.convert(Scenarios)); diff --git a/src/containers/simulation-model.js b/src/containers/simulation-model.js index 9ba7390..2f536ec 100644 --- a/src/containers/simulation-model.js +++ b/src/containers/simulation-model.js @@ -39,7 +39,7 @@ class SimulationModel extends React.Component { } static calculateState(prevState, props) { - const simulationModel = SimulationModelStore.getState().find(m => m._id === props.match.params.simulationModel); + const simulationModel = SimulationModelStore.getState().find(m => m.id === props.match.params.simulationModel); return { simulationModel: simulationModel || {}, @@ -66,11 +66,11 @@ class SimulationModel extends React.Component { token: this.state.sessionToken }); - this.props.history.push('/simulations/' + this.state.simulationModel.simulation); + this.props.history.push('/scenarios/' + this.state.simulationModel.scenarioID); } discardChanges = () => { - this.props.history.push('/simulations/' + this.state.simulationModel.simulation); + this.props.history.push('/scenarios/' + this.state.simulationModel.scenarioID); } handleSimulatorChange = simulator => { @@ -141,14 +141,14 @@ class SimulationModel extends React.Component {
      - Start Parameters + Start Parameters - +
      - + diff --git a/src/data-managers/scenarios-data-manager.js b/src/data-managers/scenarios-data-manager.js new file mode 100644 index 0000000..136ee3d --- /dev/null +++ b/src/data-managers/scenarios-data-manager.js @@ -0,0 +1,60 @@ +/** + * File: scenarios-data-manager.js + * Author: Sonja Happ + * Date: 20.08.2019 + * + * 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 RestDataManager from './rest-data-manager'; +import RestAPI from "../api/rest-api"; +import AppDispatcher from "../app-dispatcher"; + +class ScenariosDataManager extends RestDataManager { + constructor() { + super('scenario', '/scenarios'); + } + + getSimulationModels(token, id) { + RestAPI.get(this.makeURL('/scenarios/' + id + '/models'), token).then(response => { + AppDispatcher.dispatch({ + type: 'scenarios/simulationmodels', + simulationmodels: response.models + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'scenarios/simulationmodels-error', + error: error + }); + }); + } + + getDashboards(token, id) { + RestAPI.get(this.makeURL('/scenarios/' + id + '/dashboards'), token).then(response => { + AppDispatcher.dispatch({ + type: 'scenarios/dashboards', + dashboards: response.dashboards + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'scenarios/dashboards-error', + error: error + }); + }); + } + +} +export default new ScenariosDataManager(); diff --git a/src/stores/scenario-store.js b/src/stores/scenario-store.js new file mode 100644 index 0000000..c7e4dc4 --- /dev/null +++ b/src/stores/scenario-store.js @@ -0,0 +1,63 @@ +/** + * File: scenario-store.js + * Author: Sonja Happ + * Date: 20.08.2019 + * + * 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 . + ************************************************************s*****************/ + +import ArrayStore from './array-store'; +import ScenariosDataManager from '../data-managers/scenarios-data-manager'; +import UsersDataManager from "../data-managers/users-data-manager"; +import SimulatorDataDataManager from "../data-managers/simulator-data-data-manager"; +import {ReduceStore} from "flux/utils"; +import AppDispatcher from "../app-dispatcher"; + +//export default new ArrayStore('scenarios', ScenariosDataManager); + + +class ScenariosStore extends ReduceStore { + constructor() { + super('scenarios', ScenariosDataManager); + } + + getInitialState() { + return { + scenarios: [], + + }; + } + + reduce(state, action) { + switch (action.type) { + case 'scenarios/load-models': + // request simulation model data of scenario + ScenariosDataManager.getSimulationModels(action.token, action.scenarioID); + + return Object.assign({}, state, { token: action.token, simulationmodels: action.simulationmodels}); + + case 'scenarios/load-dashboards': + // request dashboard data of scenario + ScenariosDataManager.getDashboards(action.token, action.scenarioID); + + return Object.assign({}, state, { token: action.token, dashboards: action.dashboards}); + default: + return state; + } + } +} + +export default new ScenariosStore();