1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

Merge branch '170-add-new-parameters-property-to-simulation-and-simulationmodel-which-gets-send-with-start-actions-to-villascontroller' into 'develop'

Resolve "Add new "parameters" property to Simulation and SimulationModel which gets send with start actions to VILLAScontroller"

Closes #170

See merge request acs/public/villas/VILLASweb!37
This commit is contained in:
Markus Grigull 2018-06-07 15:30:32 +02:00
commit 10b03ff8dd
10 changed files with 1415 additions and 307 deletions

1099
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,7 @@
"react-dnd-html5-backend": "^2.2.4",
"react-dom": "^15.4.2",
"react-fullscreenable": "^2.4.3",
"react-json-view": "^1.17.0",
"react-notification-system": "^0.2.13",
"react-rnd": "^7.4.0",
"react-router": "^4.1.2",

View file

@ -23,69 +23,81 @@ import React from 'react';
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
import Dialog from './dialog';
import ParametersEditor from '../parameters-editor';
class EditSimulationDialog extends React.Component {
valid: false;
valid = true;
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
name: '',
_id: ''
}
}
onClose(canceled) {
if (canceled === false) {
if (this.valid) {
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.simulation.name,
_id: this.props.simulation._id
});
}
validateForm(target) {
// check all controls
var name = true;
if (this.state.name === '') {
name = false;
this.state = {
name: '',
_id: '',
startParameters: {}
};
}
this.valid = name;
onClose = canceled => {
if (canceled) {
if (this.props.onClose != null) {
this.props.onClose();
}
// return state to control
if (target === 'name') return name ? "success" : "error";
return;
}
return "success";
}
if (this.valid && this.props.onClose != null) {
this.props.onClose(this.state);
}
}
render() {
return (
<Dialog show={this.props.show} title="Edit Simulation" buttonTitle="Save" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
<form>
<FormGroup controlId="name" validationState={this.validateForm('name')}>
<ControlLabel>Name</ControlLabel>
<FormControl type="text" placeholder="Enter name" value={this.state.name} onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
</form>
</Dialog>
);
}
handleChange = event => {
this.setState({ [event.target.id]: event.target.value });
}
resetState = () => {
this.setState({
name: this.props.simulation.name,
_id: this.props.simulation._id,
startParameters: this.props.simulation.startParameters || {}
});
}
handleStartParametersChange = startParameters => {
this.setState({ startParameters });
}
validateForm(target) {
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 <Dialog show={this.props.show} title='Edit Simulation' buttonTitle='Save' onClose={this.onClose} onReset={this.resetState} valid={true}>
<form>
<FormGroup controlId='name' validationState={this.validateForm('name')}>
<ControlLabel>Name</ControlLabel>
<FormControl type='text' placeholder='Enter name' value={this.state.name} onChange={this.handleChange} />
<FormControl.Feedback />
</FormGroup>
<FormGroup controlId='startParameters'>
<ControlLabel>Start Parameters</ControlLabel>
<ParametersEditor content={this.state.startParameters} onChange={this.handleStartParametersChange} />
</FormGroup>
</form>
</Dialog>;
}
}
export default EditSimulationDialog;

View file

@ -23,118 +23,133 @@ import React from 'react';
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
import Dialog from './dialog';
import ParametersEditor from '../parameters-editor';
class ImportSimulationDialog extends React.Component {
valid = false;
imported = false;
valid = false;
imported = false;
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
name: '',
models: [],
};
}
onClose(canceled) {
if (canceled === false) {
this.props.onClose(this.state);
} else {
this.props.onClose();
}
}
handleChange(e, index) {
if (e.target.id === 'simulator') {
const models = this.state.models;
models[index].simulator = JSON.parse(e.target.value);
this.setState({ models });
} else {
this.setState({ [e.target.id]: e.target.value });
}
}
resetState() {
this.setState({ name: '', models: [] });
this.imported = false;
}
loadFile(fileList) {
// get file
const file = fileList[0];
if (!file.type.match('application/json')) {
return;
this.state = {
name: '',
models: [],
startParameters: {}
};
}
// create file reader
var reader = new FileReader();
var self = this;
onClose = canceled => {
if (canceled) {
if (this.props.onClose != null) {
this.props.onClose();
}
reader.onload = function(event) {
// read simulator
const simulation = JSON.parse(event.target.result);
simulation.models.forEach(model => {
model.simulator = {
node: self.props.nodes[0]._id,
simulator: 0
return;
}
if (this.valid && this.props.onClose != null) {
this.props.onClose(this.state);
}
});
self.imported = true;
self.setState({ name: simulation.name, models: simulation.models });
};
reader.readAsText(file);
}
validateForm(target) {
// check all controls
let name = true;
if (this.state.name === '') {
name = false;
}
this.valid = name;
handleChange(e, index) {
if (e.target.id === 'simulator') {
const models = this.state.models;
models[index].simulator = JSON.parse(e.target.value);
// return state to control
if (target === 'name') return name ? "success" : "error";
}
this.setState({ models });
render() {
return (
<Dialog show={this.props.show} title="Import Simulation" buttonTitle="Import" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
<form>
<FormGroup controlId="file">
<ControlLabel>Simulation File</ControlLabel>
<FormControl type="file" onChange={(e) => this.loadFile(e.target.files)} />
</FormGroup>
return;
}
this.setState({ [e.target.id]: e.target.value });
}
<FormGroup controlId="name" validationState={this.validateForm('name')}>
<ControlLabel>Name</ControlLabel>
<FormControl readOnly={!this.imported} type="text" placeholder="Enter name" value={this.state.name} onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
resetState = () => {
this.setState({ name: '', models: [], startParameters: {} });
{this.state.models.map((model, index) => (
<FormGroup controlId="simulator" key={index}>
<ControlLabel>{model.name} - Simulator</ControlLabel>
<FormControl componentClass="select" placeholder="Select simulator" value={JSON.stringify({ node: model.simulator.node, simulator: model.simulator.simulator})} onChange={(e) => this.handleChange(e, index)}>
{this.props.nodes.map(node => (
node.simulators.map((simulator, index) => (
<option key={node._id + index} value={JSON.stringify({ node: node._id, simulator: index })}>{node.name}/{simulator.name}</option>
))
))}
</FormControl>
</FormGroup>
))}
</form>
</Dialog>
);
}
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 simulation = JSON.parse(onloadEvent.target.result);
// simulation.models.forEach(model => {
// model.simulator = {
// node: self.props.nodes[0]._id,
// simulator: 0
// };
// });
self.imported = true;
self.valid = true;
self.setState({ name: simulation.name, models: simulation.models, startParameters: simulation.startParameters });
};
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 <Dialog show={this.props.show} title="Import Simulation" buttonTitle="Import" onClose={this.onClose} onReset={this.resetState} valid={this.valid}>
<form>
<FormGroup controlId="file">
<ControlLabel>Simulation File</ControlLabel>
<FormControl type="file" onChange={this.loadFile} />
</FormGroup>
<FormGroup controlId="name" validationState={this.validateForm('name')}>
<ControlLabel>Name</ControlLabel>
<FormControl readOnly={this.imported === false} type="text" placeholder="Enter name" value={this.state.name} onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
<FormGroup>
<ControlLabel>Start Parameters</ControlLabel>
<ParametersEditor content={this.state.startParameters} onChange={this.handleStartParametersChange} disabled={this.imported === false} />
</FormGroup>
{/* {this.state.models.map((model, index) => (
<FormGroup controlId="simulator" key={index}>
<ControlLabel>{model.name} - Simulator</ControlLabel>
<FormControl componentClass="select" placeholder="Select simulator" value={JSON.stringify({ node: model.simulator.node, simulator: model.simulator.simulator})} onChange={(e) => this.handleChange(e, index)}>
{this.props.nodes.map(node => (
node.simulators.map((simulator, index) => (
<option key={node._id + index} value={JSON.stringify({ node: node._id, simulator: index })}>{node.name}/{simulator.name}</option>
))
))}
</FormControl>
</FormGroup>
))} */}
</form>
</Dialog>;
}
}
export default ImportSimulationDialog;

View file

@ -23,63 +23,77 @@ import React from 'react';
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
import Dialog from './dialog';
import ParametersEditor from '../parameters-editor';
class NewSimulationDialog extends React.Component {
valid: false;
valid = false;
constructor(props) {
super(props);
constructor(props) {
super(props);
this.state = {
name: ''
};
}
onClose(canceled) {
if (canceled === false) {
if (this.valid) {
this.props.onClose(this.state);
}
} else {
this.props.onClose();
}
}
handleChange(e) {
this.setState({ [e.target.id]: e.target.value });
}
resetState() {
this.setState({ name: '' });
}
validateForm(target) {
// check all controls
var name = true;
if (this.state.name === '') {
name = false;
this.state = {
name: '',
startParameters: {}
};
}
this.valid = name;
onClose = canceled => {
if (canceled) {
if (this.props.onClose != null) {
this.props.onClose();
}
return;
}
// return state to control
if (target === 'name') return name ? "success" : "error";
}
if (this.valid && this.props.onClose != null) {
this.props.onClose(this.state);
}
}
render() {
return (
<Dialog show={this.props.show} title="New Simulation" buttonTitle="Add" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
<form>
<FormGroup controlId="name" validationState={this.validateForm('name')}>
<ControlLabel>Name</ControlLabel>
<FormControl type="text" placeholder="Enter name" value={this.state.name} onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
</form>
</Dialog>
);
}
handleChange = event => {
this.setState({ [event.target.id]: event.target.value });
}
resetState = () => {
this.setState({ name: '', startParameters: {} });
}
handleStartParametersChange = startParameters => {
this.setState({ startParameters });
}
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 <Dialog show={this.props.show} title="New Simulation" buttonTitle="Add" onClose={this.onClose} onReset={this.resetState} valid={this.valid}>
<form>
<FormGroup controlId="name" validationState={this.validateForm('name')}>
<ControlLabel>Name</ControlLabel>
<FormControl type="text" placeholder="Enter name" value={this.state.name} onChange={this.handleChange} />
<FormControl.Feedback />
</FormGroup>
<FormGroup>
<ControlLabel>Start Parameters</ControlLabel>
<ParametersEditor content={this.state.startParameters} onChange={this.handleStartParametersChange} />
</FormGroup>
</form>
</Dialog>;
}
}
export default NewSimulationDialog;

View file

@ -0,0 +1,80 @@
/**
* File: header.js
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
* Date: 06.06.2018
*
* 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 <http://www.gnu.org/licenses/>.
******************************************************************************/
import React from 'react';
import PropTypes from 'prop-types';
import JsonView from 'react-json-view';
class ParametersEditor extends React.Component {
onAdd = event => {
if (this.props.onChange != null) {
this.props.onChange(JSON.parse(JSON.stringify(event.updated_src)));
}
}
onEdit = event => {
if (this.props.onChange != null) {
this.props.onChange(JSON.parse(JSON.stringify(event.updated_src)));
}
}
onDelete = event => {
if (this.props.onChange != null) {
this.props.onChange(JSON.parse(JSON.stringify(event.updated_src)));
}
}
render() {
const containerStyle = {
minHeight: '100px',
paddingTop: '5px',
paddingBottom: '5px',
paddingLeft: '8px',
border: '1px solid lightgray'
};
return <div style={containerStyle}>
<JsonView
src={this.props.content}
name={false}
displayDataTypes={false}
onAdd={this.props.disabled ? undefined : this.onAdd}
onEdit={this.props.disabled ? undefined : this.onEdit}
onDelete={this.props.disabled ? undefined : this.onDelete}
/>
</div>;
}
}
ParametersEditor.PropTypes = {
content: PropTypes.object,
onChange: PropTypes.func,
disabled: PropTypes.bool
};
ParametersEditor.defaultProps = {
content: {},
disabled: false
};
export default ParametersEditor;

View file

@ -21,7 +21,7 @@
import React from 'react';
import { Container } from 'flux/utils';
import { Button, Col, Form } from 'react-bootstrap';
import { Button, Col, Form, ControlLabel } from 'react-bootstrap';
import SimulationModelStore from '../stores/simulation-model-store';
import UserStore from '../stores/user-store';
@ -31,6 +31,7 @@ import SelectSimulator from './select-simulator';
import SelectFile from './select-file';
import SignalMapping from '../components/signal-mapping';
import EditableHeader from '../components/editable-header';
import ParametersEditor from '../components/parameters-editor';
class SimulationModel extends React.Component {
static getStores() {
@ -114,6 +115,14 @@ class SimulationModel extends React.Component {
this.setState({ simulationModel });
}
handleStartParametersChange = startParameters => {
const simulationModel = this.state.simulationModel;
simulationModel.startParameters = startParameters;
this.setState({ simulationModel });
}
render() {
const buttonStyle = {
marginRight: '10px'
@ -129,6 +138,17 @@ class SimulationModel extends React.Component {
<SelectFile disabled type='model' name='Model' onChange={this.handleModelChange} value={this.state.simulationModel.model} />
<SelectFile disabled type='configuration' name='Configuration' onChange={this.handleConfigurationChange} value={this.state.simulationModel.configuration} />
<div>
<Col componentClass={ControlLabel} sm={3} md={2}>
Start Parameters
</Col>
<Col sm={9} md={10}>
<ParametersEditor content={this.state.simulationModel.startParameters} onChange={this.handleStartParametersChange} />
</Col>
</div>
</Col>
<Col xs={12} sm={6}>

View file

@ -61,7 +61,7 @@ class Simulation extends React.Component {
// load models
let simulationModels = [];
if (simulation.models != null) {
simulationModels = SimulationModelStore.getState().filter(m => simulation.models.includes(m._id));
simulationModels = SimulationModelStore.getState().filter(m => m != null && simulation.models.includes(m._id));
}
return {
@ -221,6 +221,10 @@ class Simulation extends React.Component {
continue;
}
if (action.data.action === 'start') {
action.data.parameters = this.state.simulationModels[index].startParameters;
}
AppDispatcher.dispatch({
type: 'simulators/start-action',
simulator,

View file

@ -28,6 +28,7 @@ import AppDispatcher from '../app-dispatcher';
import SimulationStore from '../stores/simulation-store';
import UserStore from '../stores/user-store';
import SimulatorStore from '../stores/simulator-store';
import SimulationModelStore from '../stores/simulation-model-store';
import Table from '../components/table';
import TableColumn from '../components/table-column';
@ -40,14 +41,21 @@ import DeleteDialog from '../components/dialog/delete-dialog';
class Simulations extends Component {
static getStores() {
return [ SimulationStore, UserStore, SimulatorStore ];
return [ SimulationStore, UserStore, SimulatorStore, SimulationModelStore ];
}
static calculateState() {
const simulations = SimulationStore.getState();
const simulationModels = SimulationModelStore.getState();
const simulators = SimulatorStore.getState();
const sessionToken = UserStore.getState().token;
return {
simulations: SimulationStore.getState(),
simulators: SimulatorStore.getState(),
sessionToken: UserStore.getState().token,
simulations,
simulationModels,
simulators,
sessionToken,
newModal: false,
deleteModal: false,
@ -59,13 +67,50 @@ class Simulations extends Component {
};
}
componentWillMount() {
componentDidMount() {
AppDispatcher.dispatch({
type: 'simulations/start-load',
token: this.state.sessionToken
});
}
componentDidUpdate() {
const simulationModelIds = [];
const simulatorIds = [];
for (let simulation of this.state.simulations) {
for (let modelId of simulation.models) {
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 });
@ -121,7 +166,7 @@ class Simulations extends Component {
closeEditModal(data) {
this.setState({ editModal : false });
if (data) {
if (data != null) {
AppDispatcher.dispatch({
type: 'simulations/start-edit',
data,
@ -195,10 +240,16 @@ class Simulations extends Component {
runAction = action => {
for (let index of this.state.selectedSimulations) {
for (let model of this.state.simulations[index].models) {
// 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 === model.simulator) {
if (sim._id === simulationModel.simulator) {
simulator = sim;
}
}
@ -206,6 +257,10 @@ class Simulations extends Component {
if (simulator == null) {
continue;
}
if (action.data.action === 'start') {
action.data.parameters = Object.assign({}, this.state.simulations[index].startParameters, simulationModel.startParameters);
}
AppDispatcher.dispatch({
type: 'simulators/start-action',

View file

@ -21,4 +21,4 @@
import RestDataManager from './rest-data-manager';
export default new RestDataManager('simulation', '/simulations', [ '_id', 'name', 'projects', 'models' ]);
export default new RestDataManager('simulation', '/simulations', [ '_id', 'name', 'projects', 'models', 'startParameters' ]);