mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Add visualization list and detailed view
Placeholder widgets are displayed, modifable but not updated yet
This commit is contained in:
parent
2fa75f0e58
commit
c6677e4553
25 changed files with 1036 additions and 264 deletions
|
@ -14,6 +14,7 @@
|
|||
"react-dnd": "^2.2.4",
|
||||
"react-dnd-html5-backend": "^2.2.4",
|
||||
"react-dom": "^15.4.2",
|
||||
"react-rnd": "^4.2.2",
|
||||
"react-router": "^3.0.2",
|
||||
"superagent": "^3.5.0"
|
||||
},
|
||||
|
|
|
@ -7,10 +7,20 @@
|
|||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
|
||||
|
||||
import Dialog from './dialog';
|
||||
|
||||
class EditSimulatorDialog extends Component {
|
||||
static propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
simulator: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
valid: false;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
@ -19,23 +29,15 @@ class EditSimulatorDialog extends Component {
|
|||
simulatorid: '1',
|
||||
endpoint: '',
|
||||
_id: ''
|
||||
};
|
||||
}
|
||||
|
||||
onClose(canceled) {
|
||||
if (canceled === false) {
|
||||
this.props.onClose(this.state);
|
||||
} else {
|
||||
this.props.onClose();
|
||||
}
|
||||
|
||||
this.closeModal = this.closeModal.bind(this);
|
||||
this.cancelModal = this.cancelModal.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.validateForm = this.validateForm.bind(this);
|
||||
this.resetState = this.resetState.bind(this);
|
||||
}
|
||||
|
||||
valid: false
|
||||
|
||||
closeModal() {
|
||||
this.props.onClose(this.state);
|
||||
}
|
||||
|
||||
cancelModal() {
|
||||
this.props.onClose(null);
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
|
@ -80,33 +82,22 @@ class EditSimulatorDialog extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<Modal show={this.props.show} onEnter={this.resetState}>
|
||||
<Modal.Header>
|
||||
<Modal.Title>Edit Simulator</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
<form>
|
||||
<FormGroup controlId="name" validationState={this.validateForm('name')}>
|
||||
<ControlLabel>Name</ControlLabel>
|
||||
<FormControl type="text" placeholder="Enter name" value={this.state.name} onChange={this.handleChange} />
|
||||
</FormGroup>
|
||||
<FormGroup controlId="simulatorid" validationState={this.validateForm('simulatorid')}>
|
||||
<ControlLabel>Simulator ID</ControlLabel>
|
||||
<FormControl type="number" placeholder="Enter simulator ID" value={this.state.simulatorid} onChange={this.handleChange} />
|
||||
</FormGroup>
|
||||
<FormGroup controlId="endpoint" validationState={this.validateForm('endpoint')}>
|
||||
<ControlLabel>Endpoint</ControlLabel>
|
||||
<FormControl type="text" placeholder="Enter endpoint" value={this.state.endpoint} onChange={this.handleChange} />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button onClick={this.cancelModal}>Cancel</Button>
|
||||
<Button bsStyle="primary" onClick={this.closeModal} disabled={!this.valid}>Save</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
<Dialog show={this.props.show} title="Edit Simulator" 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)} />
|
||||
</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)} />
|
||||
</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)} />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
82
src/components/dialog-edit-visualization.js
Normal file
82
src/components/dialog-edit-visualization.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* File: dialog-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
|
||||
* 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 EditVisualizationDialog extends Component {
|
||||
static propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
visualization: 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.visualization.name,
|
||||
_id: this.props.visualization._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 Visualization" 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)} />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EditVisualizationDialog;
|
|
@ -7,34 +7,35 @@
|
|||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import { FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
|
||||
|
||||
import Dialog from './dialog';
|
||||
|
||||
class NewSimulatorDialog extends Component {
|
||||
static propTypes = {
|
||||
show: PropTypes.bool.isRequired,
|
||||
onClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
valid: false;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
this.state = {
|
||||
name: '',
|
||||
simulatorid: '1',
|
||||
endpoint: ''
|
||||
};
|
||||
}
|
||||
|
||||
onClose(canceled) {
|
||||
if (canceled === false) {
|
||||
this.props.onClose(this.state);
|
||||
} else {
|
||||
this.props.onClose();
|
||||
}
|
||||
|
||||
this.closeModal = this.closeModal.bind(this);
|
||||
this.cancelModal = this.cancelModal.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.validateForm = this.validateForm.bind(this);
|
||||
this.resetState = this.resetState.bind(this);
|
||||
}
|
||||
|
||||
valid: false
|
||||
|
||||
closeModal() {
|
||||
this.props.onClose(this.state);
|
||||
}
|
||||
|
||||
cancelModal() {
|
||||
this.props.onClose(null);
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
|
@ -74,33 +75,22 @@ class NewSimulatorDialog extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<Modal show={this.props.show} onEnter={this.resetState}>
|
||||
<Modal.Header>
|
||||
<Modal.Title>New Simulator</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
<form>
|
||||
<FormGroup controlId="name" validationState={this.validateForm('name')}>
|
||||
<ControlLabel>Name</ControlLabel>
|
||||
<FormControl type="text" placeholder="Enter name" value={this.state.name} onChange={this.handleChange} />
|
||||
</FormGroup>
|
||||
<FormGroup controlId="simulatorid" validationState={this.validateForm('simulatorid')}>
|
||||
<ControlLabel>Simulator ID</ControlLabel>
|
||||
<FormControl type="number" placeholder="Enter simulator ID" value={this.state.simulatorid} onChange={this.handleChange} />
|
||||
</FormGroup>
|
||||
<FormGroup controlId="endpoint" validationState={this.validateForm('endpoint')}>
|
||||
<ControlLabel>Endpoint</ControlLabel>
|
||||
<FormControl type="text" placeholder="Enter endpoint" value={this.state.endpoint} onChange={this.handleChange} />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button onClick={this.cancelModal}>Cancel</Button>
|
||||
<Button bsStyle="primary" onClick={this.closeModal} disabled={!this.valid}>Add</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
<Dialog show={this.props.show} title="New Simulator" 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)} />
|
||||
</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)} />
|
||||
</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)} />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
77
src/components/dialog-new-visualization.js
Normal file
77
src/components/dialog-new-visualization.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* File: dialog-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
|
||||
* 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 NewVisualzationDialog 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";
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Dialog show={this.props.show} title="New Visualization" 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)} />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default NewVisualzationDialog;
|
49
src/components/dialog.js
Normal file
49
src/components/dialog.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* File: dialog.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 { Modal, Button } from 'react-bootstrap';
|
||||
|
||||
class Dialog extends Component {
|
||||
static propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
show: PropTypes.bool.isRequired,
|
||||
buttonTitle: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
closeModal() {
|
||||
this.props.onClose(false);
|
||||
}
|
||||
|
||||
cancelModal() {
|
||||
this.props.onClose(true);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Modal show={this.props.show} onEnter={this.props.onReset}>
|
||||
<Modal.Header>
|
||||
<Modal.Title>{this.props.title}</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
{this.props.children}
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button onClick={() => this.cancelModal()}>Cancel</Button>
|
||||
<Button bsStyle="primary" onClick={() => this.closeModal()} disabled={!this.props.valid}>{this.props.buttonTitle}</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Dialog;
|
51
src/components/dropzone.js
Normal file
51
src/components/dropzone.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* File: dropzone.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, PropTypes } from 'react';
|
||||
import { DropTarget } from 'react-dnd';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const dropzoneTarget = {
|
||||
drop(props, monitor) {
|
||||
props.onDrop(monitor.getItem());
|
||||
}
|
||||
};
|
||||
|
||||
function collect(connect, monitor) {
|
||||
return {
|
||||
connectDropTarget: connect.dropTarget(),
|
||||
isOver: monitor.isOver(),
|
||||
canDrop: monitor.canDrop()
|
||||
};
|
||||
}
|
||||
|
||||
class Dropzone extends Component {
|
||||
static propTypes = {
|
||||
connectDropTarget: PropTypes.func.isRequired,
|
||||
isOver: PropTypes.bool.isRequired,
|
||||
canDrop: PropTypes.bool.isRequired,
|
||||
onDrop: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
var toolboxClass = classNames({
|
||||
'toolbox-dropzone': true,
|
||||
'toolbox-dropzone-active': this.props.isOver && this.props.canDrop && this.props.editing,
|
||||
'toolbox-dropzone-editing': this.props.editing
|
||||
});
|
||||
|
||||
return this.props.connectDropTarget(
|
||||
<div className={toolboxClass}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DropTarget('widget', dropzoneTarget, collect)(Dropzone);
|
|
@ -21,6 +21,7 @@ class SidebarMenu extends Component {
|
|||
<li><Link to="/projects" activeClassName="active">Projects</Link></li>
|
||||
<li><Link to="/simulation" activeClassName="active">Simulations</Link></li>
|
||||
<li><Link to="/simulators" activeClassName="active">Simulators</Link></li>
|
||||
<li><Link to="/visualizations" activeClassName="active">Visualizations</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
|
75
src/components/table-control-link.js
Normal file
75
src/components/table-control-link.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* 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,5 +1,5 @@
|
|||
/**
|
||||
* File: table.js
|
||||
* 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
|
||||
|
|
52
src/components/toolbox-item.js
Normal file
52
src/components/toolbox-item.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* File: toolbox-item.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, PropTypes } from 'react';
|
||||
import { DragSource } from 'react-dnd';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const toolboxItemSource = {
|
||||
beginDrag(props) {
|
||||
return {
|
||||
name: props.name
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function collect(connect, monitor) {
|
||||
return {
|
||||
connectDragSource: connect.dragSource(),
|
||||
isDragging: monitor.isDragging()
|
||||
}
|
||||
}
|
||||
|
||||
class ToolboxItem extends Component {
|
||||
static propTypes = {
|
||||
connectDragSource: PropTypes.func.isRequired,
|
||||
isDragging: PropTypes.bool.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
var itemClass = classNames({
|
||||
'toolbox-item': true,
|
||||
'toolbox-item-dragging': this.props.isDragging
|
||||
});
|
||||
var dropEffect = 'copy';
|
||||
|
||||
return this.props.connectDragSource(
|
||||
<span className={itemClass}>
|
||||
{this.props.name}
|
||||
</span>
|
||||
, {dropEffect});
|
||||
}
|
||||
}
|
||||
|
||||
export default DragSource('widget', toolboxItemSource, collect)(ToolboxItem);
|
65
src/components/widget.js
Normal file
65
src/components/widget.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* File: widget.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 Rnd from 'react-rnd';
|
||||
|
||||
import '../styles/widgets.css';
|
||||
|
||||
class Widget extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.resizeStop = this.resizeStop.bind(this);
|
||||
this.dragStop = this.dragStop.bind(this);
|
||||
}
|
||||
|
||||
resizeStop(direction, styleSize, clientSize, delta) {
|
||||
// update widget
|
||||
var widget = this.props.data;
|
||||
widget.width = styleSize.width;
|
||||
widget.height = styleSize.height;
|
||||
|
||||
this.props.onWidgetChange(widget);
|
||||
}
|
||||
|
||||
dragStop(event, ui) {
|
||||
// update widget
|
||||
var widget = this.props.data;
|
||||
widget.x = ui.position.left;
|
||||
widget.y = ui.position.top;
|
||||
|
||||
this.props.onWidgetChange(widget);
|
||||
}
|
||||
|
||||
render() {
|
||||
const widget = this.props.data;
|
||||
|
||||
if (this.props.editing) {
|
||||
return (
|
||||
<Rnd
|
||||
ref={c => { this.rnd = c; }}
|
||||
initial={{ x: Number(widget.x), y: Number(widget.y), width: widget.width, height: widget.height }}
|
||||
bounds={'parent'}
|
||||
className="widget"
|
||||
onResizeStop={this.resizeStop}
|
||||
onDragStop={this.dragStop}
|
||||
>
|
||||
<span>{widget.name}</span>
|
||||
</Rnd>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="widget" style={{ width: Number(widget.width), height: Number(widget.height), left: Number(widget.x), top: Number(widget.y), position: 'relative' }}>{widget.name}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Widget;
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import { Container } from 'flux/utils';
|
||||
import { DragDropContext } from 'react-dnd';
|
||||
import HTML5Backend from 'react-dnd-html5-backend';
|
||||
|
||||
// import AppDispatcher from '../app-dispatcher';
|
||||
import VillasStore from '../stores/villas-store';
|
||||
|
@ -52,4 +54,4 @@ class App extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default Container.create(App);
|
||||
export default DragDropContext(HTML5Backend)(Container.create(App));
|
||||
|
|
|
@ -19,18 +19,6 @@ import NewSimulatorDialog from '../components/dialog-new-simulator';
|
|||
import EditSimulatorDialog from '../components/dialog-edit-simulator';
|
||||
|
||||
class Simulators extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.showNewModal = this.showNewModal.bind(this);
|
||||
this.closeNewModal = this.closeNewModal.bind(this);
|
||||
this.showDeleteModal = this.showDeleteModal.bind(this);
|
||||
this.confirmDeleteModal = this.confirmDeleteModal.bind(this);
|
||||
this.cancelDeleteModal = this.cancelDeleteModal.bind(this);
|
||||
this.showEditModal = this.showEditModal.bind(this);
|
||||
this.closeEditModal = this.closeEditModal.bind(this);
|
||||
}
|
||||
|
||||
static getStores() {
|
||||
return [ SimulatorStore ];
|
||||
}
|
||||
|
@ -52,17 +40,13 @@ class Simulators extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
showNewModal() {
|
||||
this.setState({ newModal: true });
|
||||
}
|
||||
|
||||
closeNewModal(data) {
|
||||
this.setState({ newModal : false });
|
||||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-add',
|
||||
simulator: data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -80,16 +64,12 @@ class Simulators extends Component {
|
|||
this.setState({ deleteModal: true, modalSimulator: deleteSimulator });
|
||||
}
|
||||
|
||||
cancelDeleteModal() {
|
||||
this.setState({ deleteModal: false });
|
||||
}
|
||||
|
||||
confirmDeleteModal() {
|
||||
this.setState({ deleteModal: false });
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-remove',
|
||||
simulator: this.state.modalSimulator
|
||||
data: this.state.modalSimulator
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -112,7 +92,7 @@ class Simulators extends Component {
|
|||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-edit',
|
||||
simulator: data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -129,13 +109,13 @@ class Simulators extends Component {
|
|||
<div>
|
||||
<h1>Simulators</h1>
|
||||
|
||||
<ControlTable columns={columns} data={this.state.simulators} width='100%' onEdit={this.showEditModal} onDelete={this.showDeleteModal} />
|
||||
<ControlTable columns={columns} data={this.state.simulators} width='100%' onEdit={(id) => this.showEditModal(id)} onDelete={(id) => this.showDeleteModal(id)} />
|
||||
|
||||
<Button onClick={this.showNewModal}>New Simulator</Button>
|
||||
<Button onClick={() => this.setState({ newModal: true })}>New Simulator</Button>
|
||||
|
||||
<NewSimulatorDialog show={this.state.newModal} onClose={this.closeNewModal} />
|
||||
<NewSimulatorDialog show={this.state.newModal} onClose={(data) => this.closeNewModal(data)} />
|
||||
|
||||
<EditSimulatorDialog show={this.state.editModal} onClose={this.closeEditModal} simulator={this.state.modalSimulator} />
|
||||
<EditSimulatorDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} simulator={this.state.modalSimulator} />
|
||||
|
||||
<Modal show={this.state.deleteModal}>
|
||||
<Modal.Header>
|
||||
|
@ -147,8 +127,8 @@ class Simulators extends Component {
|
|||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button onClick={this.cancelDeleteModal}>Cancel</Button>
|
||||
<Button bsStyle="danger" onClick={this.confirmDeleteModal}>Delete</Button>
|
||||
<Button onClick={() => this.setState({ deleteModal: false })}>Cancel</Button>
|
||||
<Button bsStyle="danger" onClick={() => this.confirmDeleteModal()}>Delete</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</div>
|
||||
|
|
96
src/containers/visualization.js
Normal file
96
src/containers/visualization.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* File: visualization.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 { Container } from 'flux/utils';
|
||||
import { Button } from 'react-bootstrap';
|
||||
|
||||
import ToolboxItem from '../components/toolbox-item';
|
||||
import Dropzone from '../components/dropzone';
|
||||
import Widget from '../components/widget';
|
||||
import VisualizationStore from '../stores/visualization-store';
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
|
||||
class Visualization extends Component {
|
||||
static getStores() {
|
||||
return [ VisualizationStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
visualizations: VisualizationStore.getState(),
|
||||
|
||||
visualization: {},
|
||||
editing: false
|
||||
}
|
||||
}
|
||||
|
||||
handleDrop(item) {
|
||||
console.log(item);
|
||||
}
|
||||
|
||||
widgetChange(widget) {
|
||||
console.log(widget);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'visualizations/start-load'
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.visualization._id !== this.props.params.visualization) {
|
||||
this.reloadVisualization();
|
||||
}
|
||||
}
|
||||
|
||||
reloadVisualization() {
|
||||
// select visualization by param id
|
||||
this.state.visualizations.forEach((visualization) => {
|
||||
if (visualization._id === this.props.params.visualization) {
|
||||
this.setState({ visualization: visualization });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>{this.state.visualization.name}</h1>
|
||||
|
||||
<div>
|
||||
{this.state.editing ? (
|
||||
<div>
|
||||
<Button bsStyle="link" onClick={() => this.setState({ editing: false })}>Save</Button>
|
||||
<Button bsStyle="link" onClick={() => this.setState({ editing: false })}>Cancel</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Button bsStyle="link" onClick={() => this.setState({ editing: true })}>Edit</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{this.state.editing &&
|
||||
<div className="toolbox">
|
||||
<ToolboxItem name="Value" type="widget" />
|
||||
</div>
|
||||
}
|
||||
|
||||
<Dropzone onDrop={item => this.handleDrop(item)} editing={this.state.editing}>
|
||||
{this.state.visualization.widgets != null &&
|
||||
this.state.visualization.widgets.map((widget, index) => (
|
||||
<Widget key={index} data={widget} onWidgetChange={this.widgetChange} editing={this.state.editing} />
|
||||
))}
|
||||
</Dropzone>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Container.create(Visualization);
|
136
src/containers/visualizations.js
Normal file
136
src/containers/visualizations.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* File: visualizations.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 } from 'react';
|
||||
import { Container } from 'flux/utils';
|
||||
import { Button, Modal } 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';
|
||||
|
||||
class Visualizations extends Component {
|
||||
static getStores() {
|
||||
return [ VisualizationStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
visualizations: VisualizationStore.getState(),
|
||||
|
||||
newModal: false,
|
||||
deleteModal: false,
|
||||
editModal: false,
|
||||
modalVisualization: {}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'visualizations/start-load'
|
||||
});
|
||||
}
|
||||
|
||||
closeNewModal(data) {
|
||||
this.setState({ newModal : false });
|
||||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'visualizations/start-add',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'visualizations/start-remove',
|
||||
data: this.state.modalVisualization
|
||||
});
|
||||
}
|
||||
|
||||
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 });
|
||||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'visualizations/start-edit',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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"/>
|
||||
|
||||
<Button onClick={() => this.setState({ newModal: true })}>New 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} />
|
||||
|
||||
<Modal show={this.state.deleteModal}>
|
||||
<Modal.Header>
|
||||
<Modal.Title>Delete Visualization</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
Are you sure you want to delete the visualization <strong>'{this.state.modalVisualization.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(Visualizations);
|
82
src/data-managers/rest-data-manager.js
Normal file
82
src/data-managers/rest-data-manager.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* File: data-manager.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 RestAPI from '../api/rest-api';
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
|
||||
class RestDataManager {
|
||||
constructor(type, url) {
|
||||
this.url = url;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
load() {
|
||||
RestAPI.get(this.url).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/loaded',
|
||||
data: response[this.type + 's']
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/load-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add(object) {
|
||||
var obj = {};
|
||||
obj[this.type] = object;
|
||||
|
||||
RestAPI.post(this.url, obj).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/added',
|
||||
data: response[this.type]
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/add-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
remove(object) {
|
||||
RestAPI.delete(this.url + '/' + object._id).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/removed',
|
||||
data: response[this.type]
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/remove-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
update(object) {
|
||||
var obj = {};
|
||||
obj[this.type] = object;
|
||||
|
||||
RestAPI.put(this.url + '/' + object._id, obj).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/edited',
|
||||
data: response[this.type]
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/edit-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default RestDataManager;
|
|
@ -7,65 +7,6 @@
|
|||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import RestAPI from '../api/rest-api';
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
import RestDataManager from './rest-data-manager';
|
||||
|
||||
const SimulatorsDataManager = {
|
||||
loadSimulators() {
|
||||
RestAPI.get('/simulators').then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/loaded',
|
||||
simulators: response.simulators
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/load-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
addSimulator(simulator) {
|
||||
RestAPI.post('/simulators', { simulator: simulator }).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/added',
|
||||
simulator: response.simulator
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/add-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
removeSimulator(simulator) {
|
||||
RestAPI.delete('/simulators/' + simulator._id).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/removed',
|
||||
simulator: simulator
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/remove-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
editSimulator(simulator) {
|
||||
RestAPI.put('/simulators/' + simulator._id, { simulator: simulator }).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/edited',
|
||||
simulator: response.simulator
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/edit-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default SimulatorsDataManager;
|
||||
export default new RestDataManager('simulator', '/simulators');
|
||||
|
|
12
src/data-managers/visualizations-data-manager.js
Normal file
12
src/data-managers/visualizations-data-manager.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* File: visualizations-data-manager.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 RestDataManager from './rest-data-manager';
|
||||
|
||||
export default new RestDataManager('visualization', '/visualizations');
|
|
@ -14,6 +14,8 @@ import App from './containers/app';
|
|||
import Home from './containers/home';
|
||||
import Projects from './containers/projects';
|
||||
import Simulators from './containers/simulators';
|
||||
import Visualization from './containers/visualization';
|
||||
import Visualizations from './containers/visualizations';
|
||||
|
||||
class Root extends Component {
|
||||
render() {
|
||||
|
@ -23,6 +25,9 @@ class Root extends Component {
|
|||
<Route path='/home' component={Home} />
|
||||
<Route path='/projects' component={Projects} />
|
||||
<Route path='/simulators' component={Simulators} />
|
||||
|
||||
<Route path='/visualizations' component={Visualizations} />
|
||||
<Route path='/visualizations/:visualization' component={Visualization} />
|
||||
</Route>
|
||||
</Router>
|
||||
);
|
||||
|
|
93
src/stores/array-store.js
Normal file
93
src/stores/array-store.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* File: array-store.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 { ReduceStore } from 'flux/utils';
|
||||
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
|
||||
class ArrayStore extends ReduceStore {
|
||||
constructor(type, dataManager) {
|
||||
super(AppDispatcher);
|
||||
|
||||
this.type = type;
|
||||
this.dataManager = dataManager;
|
||||
}
|
||||
|
||||
getInitialState() {
|
||||
return [];
|
||||
}
|
||||
|
||||
reduce(state, action) {
|
||||
var array;
|
||||
|
||||
switch (action.type) {
|
||||
case this.type + '/start-load':
|
||||
this.dataManager.load();
|
||||
return state;
|
||||
|
||||
case this.type + '/loaded':
|
||||
return action.data;
|
||||
|
||||
case this.type + '/load-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
case this.type + '/start-add':
|
||||
this.dataManager.add(action.data);
|
||||
return state;
|
||||
|
||||
case this.type + '/added':
|
||||
// state should always be immutable, thus make new copy
|
||||
array = state.slice();
|
||||
array.push(action.data);
|
||||
|
||||
return array;
|
||||
|
||||
case this.type + '/add-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
case this.type + '/start-remove':
|
||||
this.dataManager.remove(action.data);
|
||||
return state;
|
||||
|
||||
case this.type + '/removed':
|
||||
return state.filter((item) => {
|
||||
return (item !== action.data);
|
||||
});
|
||||
|
||||
case this.type + '/remove-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
case this.type + '/start-edit':
|
||||
this.dataManager.update(action.data);
|
||||
return state;
|
||||
|
||||
case this.type + '/edited':
|
||||
array = state.slice();
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (array[i]._id === action.data._id) {
|
||||
array[i] = action.data;
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
|
||||
case this.type + '/edit-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ArrayStore;
|
|
@ -7,85 +7,7 @@
|
|||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import { ReduceStore } from 'flux/utils';
|
||||
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
import ArrayStore from './array-store';
|
||||
import SimulatorsDataManager from '../data-managers/simulators-data-manager';
|
||||
|
||||
class SimulatorStore extends ReduceStore {
|
||||
constructor() {
|
||||
super(AppDispatcher);
|
||||
}
|
||||
|
||||
getInitialState() {
|
||||
return [];
|
||||
}
|
||||
|
||||
reduce(state, action) {
|
||||
var simulators;
|
||||
|
||||
switch (action.type) {
|
||||
case 'simulators/start-load':
|
||||
SimulatorsDataManager.loadSimulators();
|
||||
return state;
|
||||
|
||||
case 'simulators/loaded':
|
||||
return action.simulators;
|
||||
|
||||
case 'simulators/load-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
case 'simulators/start-add':
|
||||
SimulatorsDataManager.addSimulator(action.simulator);
|
||||
return state;
|
||||
|
||||
case 'simulators/added':
|
||||
// state should always be immutable, thus make new copy
|
||||
simulators = state.slice();
|
||||
simulators.push(action.simulator);
|
||||
|
||||
return simulators;
|
||||
|
||||
case 'simulators/add-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
case 'simulators/start-remove':
|
||||
SimulatorsDataManager.removeSimulator(action.simulator);
|
||||
return state;
|
||||
|
||||
case 'simulators/removed':
|
||||
return state.filter((simulator) => {
|
||||
return (simulator !== action.simulator)
|
||||
});
|
||||
|
||||
case 'simulators/remove-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
case 'simulators/start-edit':
|
||||
SimulatorsDataManager.editSimulator(action.simulator);
|
||||
return state;
|
||||
|
||||
case 'simulators/edited':
|
||||
simulators = state.slice();
|
||||
for (var i = 0; i < simulators.length; i++) {
|
||||
if (simulators[i]._id === action.simulator._id) {
|
||||
simulators[i] = action.simulator;
|
||||
}
|
||||
}
|
||||
|
||||
return simulators;
|
||||
|
||||
case 'simulators/edit-error':
|
||||
// TODO: Add error message
|
||||
return state;
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new SimulatorStore();
|
||||
export default new ArrayStore('simulators', SimulatorsDataManager);
|
||||
|
|
13
src/stores/visualization-store.js
Normal file
13
src/stores/visualization-store.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* File: visualization-store.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 ArrayStore from './array-store';
|
||||
import VisualizationsDataManager from '../data-managers/visualizations-data-manager';
|
||||
|
||||
export default new ArrayStore('visualizations', VisualizationsDataManager);
|
|
@ -53,7 +53,7 @@ body {
|
|||
.app-content {
|
||||
min-height: 200px;
|
||||
|
||||
margin: 20px 20px 20px 170px;
|
||||
margin: 20px 20px 20px 200px;
|
||||
padding: 15px 20px;
|
||||
|
||||
background-color: #fff;
|
||||
|
@ -67,6 +67,8 @@ body {
|
|||
.menu-sidebar {
|
||||
float: left;
|
||||
|
||||
width: 160px;
|
||||
|
||||
margin: 20px 0 0 20px;
|
||||
padding: 20px 25px 20px 25px;
|
||||
|
||||
|
@ -132,3 +134,40 @@ body {
|
|||
.table-control-button:hover {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbox
|
||||
*/
|
||||
.toolbox-dropzone {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.toolbox-dropzone-editing {
|
||||
border: 3px dashed #e1e1e1;
|
||||
}
|
||||
|
||||
.toolbox-dropzone-active {
|
||||
border-color: #aaa;
|
||||
}
|
||||
|
||||
.toolbox {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.toolbox-item {
|
||||
display: inline-block;
|
||||
|
||||
padding: 5px 10px;
|
||||
|
||||
border: 1px solid gray;
|
||||
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.toolbox-item-dragging {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
|
17
src/styles/widgets.css
Normal file
17
src/styles/widgets.css
Normal file
|
@ -0,0 +1,17 @@
|
|||
/**
|
||||
* File: widgets.css
|
||||
* 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.
|
||||
**********************************************************************************/
|
||||
|
||||
.widget {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
padding: 5px 10px;
|
||||
|
||||
border: 1px solid lightgray;
|
||||
}
|
Loading…
Add table
Reference in a new issue