1
0
Fork 0
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:
Markus Grigull 2017-03-06 22:01:33 +01:00
parent 1939df5f33
commit 01488c4939
21 changed files with 636 additions and 252 deletions

View 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;

View file

@ -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>

View file

@ -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>

View 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;

View file

@ -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>

View file

@ -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>

View file

@ -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>

View 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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View 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);

View 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);

View file

@ -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)} />

View file

@ -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>

View file

@ -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>
);
}

View file

@ -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({

View 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');

View file

@ -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>
);

View 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);