mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Add simulation(s) route
Move dialogs to components/dialog directory Change table component, add table-column component, this makes table-control and table-control-link obsolete Fix minor bugs
This commit is contained in:
parent
1939df5f33
commit
01488c4939
21 changed files with 636 additions and 252 deletions
83
src/components/dialog/edit-simulation.js
Normal file
83
src/components/dialog/edit-simulation.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* File: new-simulation.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* 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, PropTypes } from 'react';
|
||||
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
|
||||
|
||||
import Dialog from './dialog';
|
||||
|
||||
class EditSimulationDialog extends Component {
|
||||
static propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
simulation: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
valid: false;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
name: '',
|
||||
_id: ''
|
||||
}
|
||||
}
|
||||
|
||||
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.simulation.name,
|
||||
_id: this.props.simulation._id
|
||||
});
|
||||
}
|
||||
|
||||
validateForm(target) {
|
||||
// check all controls
|
||||
var name = true;
|
||||
|
||||
if (this.state.name === '') {
|
||||
name = false;
|
||||
}
|
||||
|
||||
this.valid = name;
|
||||
|
||||
// return state to control
|
||||
if (target === 'name') return name ? "success" : "error";
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EditSimulationDialog;
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* File: dialog-new-simulator.js
|
||||
* File: new-simulator.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 02.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
|
@ -87,14 +87,17 @@ class EditSimulatorDialog extends Component {
|
|||
<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>
|
||||
<FormGroup controlId="simulatorid" validationState={this.validateForm('simulatorid')}>
|
||||
<ControlLabel>Simulator ID</ControlLabel>
|
||||
<FormControl type="number" placeholder="Enter simulator ID" value={this.state.simulatorid} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
<FormGroup controlId="endpoint" validationState={this.validateForm('endpoint')}>
|
||||
<ControlLabel>Endpoint</ControlLabel>
|
||||
<FormControl type="text" placeholder="Enter endpoint" value={this.state.endpoint} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Dialog>
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* File: dialog-new-visualization.js
|
||||
* File: new-visualization.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 03.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
|
@ -72,6 +72,7 @@ class EditVisualizationDialog extends Component {
|
|||
<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>
|
76
src/components/dialog/new-simulation.js
Normal file
76
src/components/dialog/new-simulation.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
/**
|
||||
* File: new-simulation.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* 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, PropTypes } from 'react';
|
||||
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
|
||||
|
||||
import Dialog from './dialog';
|
||||
|
||||
class NewSimulationDialog extends Component {
|
||||
static propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
valid: false;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
name: ''
|
||||
};
|
||||
}
|
||||
|
||||
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: '' });
|
||||
}
|
||||
|
||||
validateForm(target) {
|
||||
// check all controls
|
||||
var 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={(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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NewSimulationDialog;
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* File: dialog-new-simulator.js
|
||||
* File: new-simulator.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 02.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
|
@ -80,14 +80,17 @@ class NewSimulatorDialog extends Component {
|
|||
<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>
|
||||
<FormGroup controlId="simulatorid" validationState={this.validateForm('simulatorid')}>
|
||||
<ControlLabel>Simulator ID</ControlLabel>
|
||||
<FormControl type="number" placeholder="Enter simulator ID" value={this.state.simulatorid} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
<FormGroup controlId="endpoint" validationState={this.validateForm('endpoint')}>
|
||||
<ControlLabel>Endpoint</ControlLabel>
|
||||
<FormControl type="text" placeholder="Enter endpoint" value={this.state.endpoint} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Dialog>
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* File: dialog-new-visualization.js
|
||||
* File: new-visualization.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 03.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
|
@ -67,6 +67,7 @@ class NewVisualzationDialog extends Component {
|
|||
<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>
|
|
@ -19,7 +19,7 @@ class SidebarMenu extends Component {
|
|||
<ul>
|
||||
<li><Link to="/home" activeClassName="active">Home</Link></li>
|
||||
<li><Link to="/projects" activeClassName="active">Projects</Link></li>
|
||||
<li><Link to="/simulation" activeClassName="active">Simulations</Link></li>
|
||||
<li><Link to="/simulations" activeClassName="active">Simulations</Link></li>
|
||||
<li><Link to="/simulators" activeClassName="active">Simulators</Link></li>
|
||||
<li><Link to="/visualizations" activeClassName="active">Visualizations</Link></li>
|
||||
</ul>
|
||||
|
|
32
src/components/table-column.js
Normal file
32
src/components/table-column.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* File: table-column.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 06.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';
|
||||
|
||||
class TableColumn extends Component {
|
||||
static defaultProps = {
|
||||
title: '',
|
||||
modifier: null,
|
||||
width: null,
|
||||
editButton: false,
|
||||
deleteButton: false,
|
||||
link: '/',
|
||||
linkKey: ''
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<th width={this.props.width}>
|
||||
{this.props.title}
|
||||
</th>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TableColumn;
|
|
@ -1,75 +0,0 @@
|
|||
/**
|
||||
* File: table-control-link.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 03.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, PropTypes } from 'react';
|
||||
import { Button, Glyphicon } from 'react-bootstrap';
|
||||
import { Link } from 'react-router';
|
||||
|
||||
class ControlLinkTable extends Component {
|
||||
static propTypes = {
|
||||
columns: PropTypes.array.isRequired,
|
||||
onEdit: PropTypes.func.isRequired,
|
||||
onDelete: PropTypes.func.isRequired,
|
||||
linkRoot: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
// create sorted rows
|
||||
var rows = this.props.data.map(row => {
|
||||
// add cells by column keys
|
||||
var rowArray = [ row._id ];
|
||||
|
||||
for (var i = 0; i < this.props.columns.length; i++) {
|
||||
if (row[this.props.columns[i].key] != null) {
|
||||
rowArray.push(row[this.props.columns[i].key].toString());
|
||||
} else {
|
||||
rowArray.push("");
|
||||
}
|
||||
}
|
||||
|
||||
return rowArray;
|
||||
});
|
||||
|
||||
return (
|
||||
<table width={this.props.width} className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
{this.props.columns.map(column => (
|
||||
<th key={column.key} width={column.width}>{column.title}</th>
|
||||
))}
|
||||
<th width="70px"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row) => (
|
||||
<tr key={row[0]}>
|
||||
{row.filter((element, index) => {
|
||||
return index !== 0;
|
||||
}).map((cell, index) => (
|
||||
<td key={index}>
|
||||
{index === 0 ? (
|
||||
<Link to={this.props.linkRoot + '/' + row[0]}>{cell}</Link>
|
||||
) : (
|
||||
{cell}
|
||||
)}
|
||||
</td>
|
||||
))}
|
||||
<td>
|
||||
<Button bsClass="table-control-button" onClick={() => this.props.onEdit(row[0])}><Glyphicon glyph="pencil" /></Button>
|
||||
<Button bsClass="table-control-button" onClick={() => this.props.onDelete(row[0])}><Glyphicon glyph="remove" /></Button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ControlLinkTable;
|
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
* File: table-control.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 02.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 { Button, Glyphicon } from 'react-bootstrap';
|
||||
|
||||
class ControlTable extends Component {
|
||||
render() {
|
||||
// create sorted rows
|
||||
var rows = this.props.data.map(row => {
|
||||
// add cells by column keys
|
||||
var rowArray = [ row._id ];
|
||||
|
||||
for (var i = 0; i < this.props.columns.length; i++) {
|
||||
if (row[this.props.columns[i].key] != null) {
|
||||
rowArray.push(row[this.props.columns[i].key].toString());
|
||||
} else {
|
||||
rowArray.push("");
|
||||
}
|
||||
}
|
||||
|
||||
return rowArray;
|
||||
});
|
||||
|
||||
return (
|
||||
<table width={this.props.width} className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
{this.props.columns.map(column => (
|
||||
<th key={column.key} width={column.width}>{column.title}</th>
|
||||
))}
|
||||
<th width="70px"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row) => (
|
||||
<tr key={row[0]}>
|
||||
{row.filter((element, index) => {
|
||||
return index !== 0;
|
||||
}).map((cell, index) => (
|
||||
<td key={index}>{cell}</td>
|
||||
))}
|
||||
<td>
|
||||
<Button bsClass="table-control-button" onClick={() => this.props.onEdit(row[0])}><Glyphicon glyph="pencil" /></Button>
|
||||
<Button bsClass="table-control-button" onClick={() => this.props.onDelete(row[0])}><Glyphicon glyph="remove" /></Button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ControlTable;
|
|
@ -8,46 +8,93 @@
|
|||
**********************************************************************************/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Table, Button, Glyphicon } from 'react-bootstrap';
|
||||
import { Link } from 'react-router';
|
||||
|
||||
import TableColumn from './table-column';
|
||||
|
||||
class CustomTable extends Component {
|
||||
static defaultProps = {
|
||||
width: null
|
||||
};
|
||||
|
||||
class Table extends Component {
|
||||
render() {
|
||||
// create sorted rows
|
||||
var rows = this.props.data.map(row => {
|
||||
// add cells by column keys
|
||||
var rowArray = [];
|
||||
// create sorted data for rows
|
||||
var rows = [];
|
||||
if (this.props.data) {
|
||||
rows = this.props.data.map((row, index) => {
|
||||
var array = [];
|
||||
|
||||
for (var i = 0; i < this.props.columns.length; i++) {
|
||||
if (row[this.props.columns[i].key] != null) {
|
||||
rowArray.push(row[this.props.columns[i].key].toString());
|
||||
} else {
|
||||
rowArray.push("");
|
||||
for (var i = 0; i < this.props.children.length; i++) {
|
||||
// only handle table-column children
|
||||
if (this.props.children[i].type === TableColumn) {
|
||||
// add content to cell
|
||||
var cell = [];
|
||||
|
||||
// add data to cell
|
||||
const dataKey = this.props.children[i].props.dataKey;
|
||||
if (dataKey && row[dataKey] != null) {
|
||||
// get content
|
||||
var content;
|
||||
const modifier = this.props.children[i].props.modifier;
|
||||
|
||||
if (modifier) {
|
||||
content = modifier(row[dataKey]);
|
||||
} else {
|
||||
content = row[dataKey].toString();
|
||||
}
|
||||
|
||||
// check if cell should be a link
|
||||
const linkKey = this.props.children[i].props.linkKey;
|
||||
if (linkKey && row[linkKey] != null) {
|
||||
cell.push(<Link to={this.props.children[i].props.link + row[linkKey]}>{content}</Link>);
|
||||
} else {
|
||||
cell.push(content);
|
||||
}
|
||||
}
|
||||
|
||||
// add buttons
|
||||
if (this.props.children[i].props.editButton) {
|
||||
const onEdit = this.props.children[i].props.onEdit;
|
||||
cell.push(<Button bsClass='table-control-button' onClick={() => onEdit(index)}><Glyphicon glyph='pencil' /></Button>);
|
||||
}
|
||||
|
||||
if (this.props.children[i].props.deleteButton) {
|
||||
const onDelete = this.props.children[i].props.onDelete;
|
||||
cell.push(<Button bsClass='table-control-button' onClick={() => onDelete(index)}><Glyphicon glyph='remove' /></Button>);
|
||||
}
|
||||
|
||||
array.push(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rowArray;
|
||||
});
|
||||
return array;
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<table width={this.props.width} className="table">
|
||||
<Table width={this.props.width} striped hover>
|
||||
<thead>
|
||||
<tr>
|
||||
{this.props.columns.map(column => (
|
||||
<th key={column.key} width={column.width}>{column.title}</th>
|
||||
))}
|
||||
{this.props.children}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, index) => (
|
||||
<tr key={index}>
|
||||
{row.map((cell, index) => (
|
||||
<td key={index}>{cell}</td>
|
||||
<td key={index}>
|
||||
{cell.map((element, index) => (
|
||||
<span key={index}>{element}</span>
|
||||
))}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Table;
|
||||
export default CustomTable;
|
||||
|
|
150
src/containers/simulation.js
Normal file
150
src/containers/simulation.js
Normal file
|
@ -0,0 +1,150 @@
|
|||
/**
|
||||
* File: simulation.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* 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 { Container } from 'flux/utils';
|
||||
import { Button, Modal, Glyphicon } from 'react-bootstrap';
|
||||
|
||||
import SimulationStore from '../stores/simulation-store';
|
||||
import SimulatorStore from '../stores/simulator-store';
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
|
||||
import Table from '../components/table';
|
||||
import TableColumn from '../components/table-column';
|
||||
import NewSimulationModelDialog from '../components/dialog/new-simulation-model';
|
||||
import EditSimulationModelDialog from '../components/dialog/edit-simulation-model';
|
||||
|
||||
class Simulation extends Component {
|
||||
static getStores() {
|
||||
return [ SimulationStore, SimulatorStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
simulations: SimulationStore.getState(),
|
||||
simulators: SimulatorStore.getState(),
|
||||
|
||||
newModal: false,
|
||||
deleteModal: false,
|
||||
editModal: false,
|
||||
modalData: {},
|
||||
|
||||
simulation: {}
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulations/start-load'
|
||||
});
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-load'
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.simulation._id !== this.props.params.simulation) {
|
||||
this.reloadSimulation();
|
||||
}
|
||||
}
|
||||
|
||||
reloadSimulation() {
|
||||
// select simulation by param id
|
||||
this.state.simulations.forEach((simulation) => {
|
||||
if (simulation._id === this.props.params.simulation) {
|
||||
// JSON.parse(JSON.stringify(obj)) = deep clone to make also copy of widget objects inside
|
||||
this.setState({ simulation: JSON.parse(JSON.stringify(simulation)) });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
closeNewModal(data) {
|
||||
this.setState({ newModal : false });
|
||||
|
||||
if (data) {
|
||||
this.state.simulation.models.push(data);
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulations/start-edit',
|
||||
data: this.state.simulation
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
confirmDeleteModal() {
|
||||
this.setState({ deleteModal: false });
|
||||
|
||||
|
||||
|
||||
/*AppDispatcher.dispatch({
|
||||
type: 'visualizations/start-remove',
|
||||
data: this.state.modalVisualization
|
||||
});*/
|
||||
}
|
||||
|
||||
closeEditModal(data) {
|
||||
this.setState({ editModal : false });
|
||||
|
||||
if (data) {
|
||||
/*AppDispatcher.dispatch({
|
||||
type: 'visualizations/start-edit',
|
||||
data: data
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
||||
getSimulatorName(id) {
|
||||
for (var i = 0; i < this.state.simulators.length; i++) {
|
||||
if (this.state.simulators[i]._id === id) {
|
||||
return this.state.simulators[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>{this.state.simulation.name}</h1>
|
||||
|
||||
<Table data={this.state.simulation.models}>
|
||||
<TableColumn title='Name' dataKey='name' />
|
||||
<TableColumn title='Simulator' dataKey='simulator' width='180' modifier={(id) => this.getSimulatorName(id)} />
|
||||
<TableColumn title='Length' dataKey='length' width='100' />
|
||||
<TableColumn title='' width='70' editButton deleteButton onEdit={(index) => this.setState({ editModal: true, modalData: this.state.simulation.models[index] })} onDelete={(index) => this.setState({ deleteModal: true, modalData: this.state.simulation.models[index] })} />
|
||||
</Table>
|
||||
|
||||
<Button onClick={() => this.setState({ newModal: true })}><Glyphicon glyph="plus" /> Simulation Model</Button>
|
||||
|
||||
<NewSimulationModelDialog show={this.state.newModal} onClose={(data) => this.closeNewModal(data)} simulators={this.state.simulators} />
|
||||
|
||||
<EditSimulationModelDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} data={this.state.modalData} />
|
||||
|
||||
<Modal show={this.state.deleteModal}>
|
||||
<Modal.Header>
|
||||
<Modal.Title>Delete Simulation Model</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
Are you sure you want to delete the simulation model <strong>'{this.state.modalData.name}'</strong>?
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button onClick={() => this.setState({ deleteModal: false })}>Cancel</Button>
|
||||
<Button bsStyle="danger" onClick={() => this.confirmDeleteModal()}>Delete</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Container.create(Simulation);
|
136
src/containers/simulations.js
Normal file
136
src/containers/simulations.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* File: simulations.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* 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 { Container } from 'flux/utils';
|
||||
import { Button, Modal, Glyphicon } from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
import SimulationStore from '../stores/simulation-store';
|
||||
|
||||
import Table from '../components/table';
|
||||
import TableColumn from '../components/table-column';
|
||||
import NewSimulationDialog from '../components/dialog/new-simulation';
|
||||
import EditSimulationDialog from '../components/dialog/edit-simulation';
|
||||
|
||||
class Simulations extends Component {
|
||||
static getStores() {
|
||||
return [ SimulationStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
simulations: SimulationStore.getState(),
|
||||
|
||||
newModal: false,
|
||||
deleteModal: false,
|
||||
editModal: false,
|
||||
modalSimulation: {}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulations/start-load'
|
||||
});
|
||||
}
|
||||
|
||||
closeNewModal(data) {
|
||||
this.setState({ newModal : false });
|
||||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulations/start-add',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
showDeleteModal(id) {
|
||||
// get simulation by id
|
||||
var deleteSimulation;
|
||||
|
||||
this.state.simulations.forEach((simulation) => {
|
||||
if (simulation._id === id) {
|
||||
deleteSimulation = simulation;
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ deleteModal: true, modalSimulation: deleteSimulation });
|
||||
}
|
||||
|
||||
confirmDeleteModal() {
|
||||
this.setState({ deleteModal: false });
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulations/start-remove',
|
||||
data: this.state.modalSimulation
|
||||
});
|
||||
}
|
||||
|
||||
showEditModal(id) {
|
||||
// get simulation by id
|
||||
var editSimulation;
|
||||
|
||||
this.state.simulations.forEach((simulation) => {
|
||||
if (simulation._id === id) {
|
||||
editSimulation = simulation;
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ editModal: true, modalSimulation: editSimulation });
|
||||
}
|
||||
|
||||
closeEditModal(data) {
|
||||
this.setState({ editModal : false });
|
||||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulations/start-edit',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Simulations</h1>
|
||||
|
||||
<Table data={this.state.simulations}>
|
||||
<TableColumn title='Name' dataKey='name' link='/simulations/' linkKey='_id' />
|
||||
<TableColumn width='70' editButton deleteButton onEdit={index => this.setState({ editModal: true, modalSimulation: this.state.simulations[index] })} onDelete={index => this.setState({ deleteModal: true, modalSimulation: this.state.simulations[index] })} />
|
||||
</Table>
|
||||
|
||||
<Button onClick={() => this.setState({ newModal: true })}><Glyphicon glyph="plus" /> Simulation</Button>
|
||||
|
||||
<NewSimulationDialog show={this.state.newModal} onClose={(data) => this.closeNewModal(data)} />
|
||||
|
||||
<EditSimulationDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} simulation={this.state.modalSimulation} />
|
||||
|
||||
<Modal show={this.state.deleteModal}>
|
||||
<Modal.Header>
|
||||
<Modal.Title>Delete Simulation</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
Are you sure you want to delete the simulation <strong>'{this.state.modalSimulation.name}'</strong>?
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button onClick={() => this.setState({ deleteModal: false })}>Cancel</Button>
|
||||
<Button bsStyle="danger" onClick={() => this.confirmDeleteModal()}>Delete</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Container.create(Simulations);
|
|
@ -9,14 +9,15 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import { Container } from 'flux/utils';
|
||||
import { Button, Modal } from 'react-bootstrap';
|
||||
import { Button, Modal, Glyphicon } from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
import SimulatorStore from '../stores/simulator-store';
|
||||
|
||||
import ControlTable from '../components/table-control';
|
||||
import NewSimulatorDialog from '../components/dialog-new-simulator';
|
||||
import EditSimulatorDialog from '../components/dialog-edit-simulator';
|
||||
import Table from '../components/table';
|
||||
import TableColumn from '../components/table-column';
|
||||
import NewSimulatorDialog from '../components/dialog/new-simulator';
|
||||
import EditSimulatorDialog from '../components/dialog/edit-simulator';
|
||||
|
||||
class Simulators extends Component {
|
||||
static getStores() {
|
||||
|
@ -51,19 +52,6 @@ class Simulators extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
showDeleteModal(id) {
|
||||
// get simulator by id
|
||||
var deleteSimulator;
|
||||
|
||||
this.state.simulators.forEach((simulator) => {
|
||||
if (simulator._id === id) {
|
||||
deleteSimulator = simulator;
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ deleteModal: true, modalSimulator: deleteSimulator });
|
||||
}
|
||||
|
||||
confirmDeleteModal() {
|
||||
this.setState({ deleteModal: false });
|
||||
|
||||
|
@ -73,19 +61,6 @@ class Simulators extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
showEditModal(id) {
|
||||
// get simulator by id
|
||||
var editSimulator;
|
||||
|
||||
this.state.simulators.forEach((simulator) => {
|
||||
if (simulator._id === id) {
|
||||
editSimulator = simulator;
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ editModal: true, modalSimulator: editSimulator });
|
||||
}
|
||||
|
||||
closeEditModal(data) {
|
||||
this.setState({ editModal : false });
|
||||
|
||||
|
@ -98,20 +73,19 @@ class Simulators extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
var columns = [
|
||||
{ title: 'Name', key: 'name' },
|
||||
{ title: 'ID', key: 'simulatorid', width: 80 },
|
||||
{ title: 'Running', key: 'running', width: 80 },
|
||||
{ title: 'Endpoint', key: 'endpoint', width: 120 }
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Simulators</h1>
|
||||
|
||||
<ControlTable columns={columns} data={this.state.simulators} width='100%' onEdit={(id) => this.showEditModal(id)} onDelete={(id) => this.showDeleteModal(id)} />
|
||||
<Table data={this.state.simulators}>
|
||||
<TableColumn title='Name' dataKey='name' />
|
||||
<TableColumn title='ID' dataKey='simulatorid' width='80' />
|
||||
<TableColumn title='Running' dataKey='running' width='80' />
|
||||
<TableColumn title='Endpoint' dataKey='endpoint' width='120' />
|
||||
<TableColumn title='' width='70' editButton deleteButton onEdit={(index) => this.setState({ editModal: true, modalSimulator: this.state.simulators[index] })} onDelete={(index) => this.setState({ deleteModal: true, modalSimulator: this.state.simulators[index] })} />
|
||||
</Table>
|
||||
|
||||
<Button onClick={() => this.setState({ newModal: true })}>New Simulator</Button>
|
||||
<Button onClick={() => this.setState({ newModal: true })}><Glyphicon glyph="plus" /> Simulator</Button>
|
||||
|
||||
<NewSimulatorDialog show={this.state.newModal} onClose={(data) => this.closeNewModal(data)} />
|
||||
|
||||
|
|
|
@ -9,14 +9,15 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import { Container } from 'flux/utils';
|
||||
import { Button, Modal } from 'react-bootstrap';
|
||||
import { Button, Modal, Glyphicon } from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
import VisualizationStore from '../stores/visualization-store';
|
||||
|
||||
import ControlLinkTable from '../components/table-control-link';
|
||||
import NewVisualzationDialog from '../components/dialog-new-visualization';
|
||||
import EditVisualizationDialog from '../components/dialog-edit-visualization';
|
||||
import Table from '../components/table';
|
||||
import TableColumn from '../components/table-column';
|
||||
import NewVisualzationDialog from '../components/dialog/new-visualization';
|
||||
import EditVisualizationDialog from '../components/dialog/edit-visualization';
|
||||
|
||||
class Visualizations extends Component {
|
||||
static getStores() {
|
||||
|
@ -30,7 +31,7 @@ class Visualizations extends Component {
|
|||
newModal: false,
|
||||
deleteModal: false,
|
||||
editModal: false,
|
||||
modalVisualization: {}
|
||||
modalData: {}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -51,19 +52,6 @@ class Visualizations extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
showDeleteModal(id) {
|
||||
// get visualization by id
|
||||
var deleteVisualization;
|
||||
|
||||
this.state.visualizations.forEach((visualization) => {
|
||||
if (visualization._id === id) {
|
||||
deleteVisualization = visualization;
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ deleteModal: true, modalVisualization: deleteVisualization });
|
||||
}
|
||||
|
||||
confirmDeleteModal() {
|
||||
this.setState({ deleteModal: false });
|
||||
|
||||
|
@ -73,19 +61,6 @@ class Visualizations extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
showEditModal(id) {
|
||||
// get visualization by id
|
||||
var editVisualization;
|
||||
|
||||
this.state.visualizations.forEach((visualization) => {
|
||||
if (visualization._id === id) {
|
||||
editVisualization = visualization;
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ editModal: true, modalVisualization: editVisualization });
|
||||
}
|
||||
|
||||
closeEditModal(data) {
|
||||
this.setState({ editModal : false });
|
||||
|
||||
|
@ -98,21 +73,20 @@ class Visualizations extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
var columns = [
|
||||
{ title: 'Name', key: 'name' }
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Visualizations</h1>
|
||||
|
||||
<ControlLinkTable columns={columns} data={this.state.visualizations} width='100%' onEdit={(id) => this.showEditModal(id)} onDelete={(id) => this.showDeleteModal(id)} linkRoot="/visualizations"/>
|
||||
<Table data={this.state.visualizations}>
|
||||
<TableColumn title='Name' dataKey='name' link='/visualizations/' linkKey='_id' />
|
||||
<TableColumn width='70' editButton deleteButton onEdit={index => this.setState({ editModal: true, modalData: this.state.visualizations[index] })} onDelete={index => this.setState({ deleteModal: true, modalData: this.state.visualizations[index] })} />
|
||||
</Table>
|
||||
|
||||
<Button onClick={() => this.setState({ newModal: true })}>New Visualization</Button>
|
||||
<Button onClick={() => this.setState({ newModal: true })}><Glyphicon glyph="plus" /> Visualization</Button>
|
||||
|
||||
<NewVisualzationDialog show={this.state.newModal} onClose={(data) => this.closeNewModal(data)} />
|
||||
|
||||
<EditVisualizationDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} visualization={this.state.modalVisualization} />
|
||||
<EditVisualizationDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} visualization={this.state.modalData} />
|
||||
|
||||
<Modal show={this.state.deleteModal}>
|
||||
<Modal.Header>
|
||||
|
@ -120,7 +94,7 @@ class Visualizations extends Component {
|
|||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
Are you sure you want to delete the visualization <strong>'{this.state.modalVisualization.name}'</strong>?
|
||||
Are you sure you want to delete the visualization <strong>'{this.state.modalData.name}'</strong>?
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
|
|
|
@ -13,6 +13,7 @@ import { ContextMenuTrigger } from 'react-contextmenu';
|
|||
import Rnd from 'react-rnd';
|
||||
|
||||
import SimulatorDataStore from '../stores/simulator-data-store';
|
||||
import WidgetValue from '../components/widget-value';
|
||||
|
||||
import '../styles/widgets.css';
|
||||
|
||||
|
@ -21,12 +22,20 @@ class Widget extends Component {
|
|||
return [ SimulatorDataStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
simulatorData: SimulatorDataStore.getState(),
|
||||
static calculateState(prevState) {
|
||||
if (prevState) {
|
||||
return {
|
||||
simulatorData: SimulatorDataStore.getState(),
|
||||
|
||||
widget: {}
|
||||
};
|
||||
sequence: prevState.sequence + 1
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
simulatorData: SimulatorDataStore.getState(),
|
||||
|
||||
sequence: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
dragStop(event, ui) {
|
||||
|
@ -50,11 +59,9 @@ class Widget extends Component {
|
|||
render() {
|
||||
const widget = this.props.data;
|
||||
|
||||
var value = '';
|
||||
|
||||
if (this.state.simulatorData.RTDS && this.state.simulatorData.RTDS.values) {
|
||||
const arr = this.state.simulatorData.RTDS.values[this.props.index];
|
||||
value = arr[arr.length - 1].y;
|
||||
var grid = this.props.grid;
|
||||
if (!grid) {
|
||||
grid = [ 1, 1 ];
|
||||
}
|
||||
|
||||
if (this.props.editing) {
|
||||
|
@ -66,16 +73,18 @@ class Widget extends Component {
|
|||
className="widget"
|
||||
onResizeStop={(direction, styleSize, clientSize, delta) => this.resizeStop(direction, styleSize, clientSize, delta)}
|
||||
onDragStop={(event, ui) => this.dragStop(event, ui)}
|
||||
moveGrid={grid}
|
||||
resizeGrid={grid}
|
||||
>
|
||||
<ContextMenuTrigger id={'widgetMenu' + this.props.index} attributes={{ style: { width: '100%', height: '100%' } }}>
|
||||
<div>{value}</div>
|
||||
<WidgetValue widget={widget} data={this.state.simulatorData} sequence={this.state.sequence} />
|
||||
</ContextMenuTrigger>
|
||||
</Rnd>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="widget" style={{ width: Number(widget.width), height: Number(widget.height), left: Number(widget.x), top: Number(widget.y), position: 'absolute' }}>
|
||||
{value}
|
||||
<WidgetValue widget={widget} data={this.state.simulatorData} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,8 @@ class RestDataManager {
|
|||
RestAPI.delete(this.url + '/' + object._id).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/removed',
|
||||
data: response[this.type]
|
||||
data: response[this.type],
|
||||
original: object
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
|
|
12
src/data-managers/simulations-data-manager.js
Normal file
12
src/data-managers/simulations-data-manager.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* File: simulation-data-manager.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* 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 RestDataManager from './rest-data-manager';
|
||||
|
||||
export default new RestDataManager('simulation', '/simulations');
|
|
@ -16,6 +16,8 @@ import Projects from './containers/projects';
|
|||
import Simulators from './containers/simulators';
|
||||
import Visualization from './containers/visualization';
|
||||
import Visualizations from './containers/visualizations';
|
||||
import Simulations from './containers/simulations';
|
||||
import Simulation from './containers/simulation';
|
||||
|
||||
class Root extends Component {
|
||||
render() {
|
||||
|
@ -28,6 +30,9 @@ class Root extends Component {
|
|||
|
||||
<Route path='/visualizations' component={Visualizations} />
|
||||
<Route path='/visualizations/:visualization' component={Visualization} />
|
||||
|
||||
<Route path='/simulations' component={Simulations} />
|
||||
<Route path='/simulations/:simulation' component={Simulation} />
|
||||
</Route>
|
||||
</Router>
|
||||
);
|
||||
|
|
13
src/stores/simulation-store.js
Normal file
13
src/stores/simulation-store.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* File: simulation-store.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* 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 ArrayStore from './array-store';
|
||||
import SimulationsDataManager from '../data-managers/simulations-data-manager';
|
||||
|
||||
export default new ArrayStore('simulations', SimulationsDataManager);
|
Loading…
Add table
Reference in a new issue