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 delete and edit dialog to simulators

This commit is contained in:
Markus Grigull 2017-03-02 16:22:57 +01:00
parent 48057a99ec
commit 2fa75f0e58
11 changed files with 447 additions and 138 deletions

View file

@ -41,6 +41,30 @@ class RestAPI {
});
});
}
delete(url) {
return new Promise(function (resolve, reject) {
request.delete(makeURL(url)).end(function (error, res) {
if (res.status !== 200) {
reject();
} else {
resolve(JSON.parse(res.text));
}
});
});
}
put(url, body) {
return new Promise(function (resolve, reject) {
request.put(makeURL(url)).send(body).end(function (error, res) {
if (res.status !== 200) {
reject();
} else {
resolve(JSON.parse(res.text));
}
});
});
}
}
export default new RestAPI();

View file

@ -0,0 +1,114 @@
/**
* File: dialog-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
* 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 { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
class EditSimulatorDialog extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
simulatorid: '1',
endpoint: '',
_id: ''
}
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) {
this.setState({ [e.target.id]: e.target.value });
}
resetState() {
this.setState({
name: this.props.simulator.name,
simulatorid: this.props.simulator.simulatorid,
endpoint: this.props.simulator.endpoint,
_id: this.props.simulator._id
});
}
validateForm(target) {
// check all controls
var simulatorid = true;
var endpoint = true;
var name = true;
if (this.state.name === '') {
name = false;
}
// test if simulatorid is a number (in a string, not type of number)
if (!/^\d+$/.test(this.state.simulatorid)) {
simulatorid = false;
}
if (this.state.endpoint === '') {
endpoint = false;
}
this.valid = simulatorid && endpoint && name;
// return state to control
if (target === 'name') return name ? "success" : "error";
else if (target === 'simulatorid') return simulatorid ? "success" : "error";
else return endpoint ? "success" : "error";
}
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>
);
}
}
export default EditSimulatorDialog;

View file

@ -7,102 +7,102 @@
* 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 } from 'react';
import { Modal, Button, FormGroup, FormControl, ControlLabel } from 'react-bootstrap';
class NewSimulatorDialog extends Component {
constructor(props) {
super(props);
class NewSimulatorDialog extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
simulatorid: '1',
endpoint: ''
}
this.state = {
name: '',
simulatorid: '1',
endpoint: ''
}
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);
}
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
valid: false
closeModal() {
this.props.onClose(this.state);
}
closeModal() {
this.props.onClose(this.state);
}
cancelModal() {
this.props.onClose(null);
}
cancelModal() {
this.props.onClose(null);
}
handleChange(e) {
this.setState({ [e.target.id]: e.target.value });
}
handleChange(e) {
this.setState({ [e.target.id]: e.target.value });
}
resetState() {
this.setState({ name: '', simulatorid: '1', endpoint: '' });
}
resetState() {
this.setState({ name: '', simulatorid: '1', endpoint: '' });
}
validateForm(target) {
// check all controls
var simulatorid = true;
var endpoint = true;
var name = true;
validateForm(target) {
// check all controls
var simulatorid = true;
var endpoint = true;
var name = true;
if (this.state.name === '') {
name = false;
}
if (this.state.name === '') {
name = false;
}
// test if simulatorid is a number (in a string, not type of number)
if (!/^\d+$/.test(this.state.simulatorid)) {
simulatorid = false;
}
// test if simulatorid is a number (in a string, not type of number)
if (!/^\d+$/.test(this.state.simulatorid)) {
simulatorid = false;
}
if (this.state.endpoint === '') {
endpoint = false;
}
if (this.state.endpoint === '') {
endpoint = false;
}
this.valid = simulatorid && endpoint && name;
this.valid = simulatorid && endpoint && name;
// return state to control
if (target === 'name') return name ? "success" : "error";
else if (target === 'simulatorid') return simulatorid ? "success" : "error";
else return endpoint ? "success" : "error";
}
// return state to control
if (target === 'name') return name ? "success" : "error";
else if (target === 'simulatorid') return simulatorid ? "success" : "error";
else return endpoint ? "success" : "error";
}
render() {
return (
<Modal show={this.props.show} onEnter={this.resetState}>
<Modal.Header>
<Modal.Title>New Simulator</Modal.Title>
</Modal.Header>
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.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}>Close</Button>
<Button bsStyle="primary" onClick={this.closeModal} disabled={!this.valid}>Add</Button>
</Modal.Footer>
</Modal>
);
}
}
<Modal.Footer>
<Button onClick={this.cancelModal}>Cancel</Button>
<Button bsStyle="primary" onClick={this.closeModal} disabled={!this.valid}>Add</Button>
</Modal.Footer>
</Modal>
);
}
}
export default NewSimulatorDialog;
export default NewSimulatorDialog;

View file

@ -0,0 +1,61 @@
/**
* File: table.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

@ -13,8 +13,6 @@ import { Container } from 'flux/utils';
// import AppDispatcher from '../app-dispatcher';
import VillasStore from '../stores/villas-store';
import '../styles/projects.css';
class Projects extends Component {
static getStores() {
return [ VillasStore ];

View file

@ -9,34 +9,40 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
import { Button } from 'react-bootstrap';
import { Button, Modal } from 'react-bootstrap';
import AppDispatcher from '../app-dispatcher';
import VillasStore from '../stores/villas-store';
import SimulatorStore from '../stores/simulator-store';
import Table from '../components/table';
import ControlTable from '../components/table-control';
import NewSimulatorDialog from '../components/dialog-new-simulator';
import '../styles/projects.css';
import EditSimulatorDialog from '../components/dialog-edit-simulator';
class Simulators extends Component {
constructor(props) {
super(props);
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
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 [ VillasStore, SimulatorStore ];
return [ SimulatorStore ];
}
static calculateState() {
return {
villas: VillasStore.getState(),
simulators: SimulatorStore.getState(),
modal: false
newModal: false,
deleteModal: false,
editModal: false,
modalSimulator: {}
};
}
@ -46,12 +52,12 @@ class Simulators extends Component {
});
}
showModal() {
this.setState({ modal: true });
showNewModal() {
this.setState({ newModal: true });
}
closeModal(data) {
this.setState({ modal : false });
closeNewModal(data) {
this.setState({ newModal : false });
if (data) {
AppDispatcher.dispatch({
@ -61,6 +67,56 @@ 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 });
}
cancelDeleteModal() {
this.setState({ deleteModal: false });
}
confirmDeleteModal() {
this.setState({ deleteModal: false });
AppDispatcher.dispatch({
type: 'simulators/start-remove',
simulator: this.state.modalSimulator
});
}
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 });
if (data) {
AppDispatcher.dispatch({
type: 'simulators/start-edit',
simulator: data
});
}
}
render() {
var columns = [
{ title: 'Name', key: 'name' },
@ -73,11 +129,28 @@ class Simulators extends Component {
<div>
<h1>Simulators</h1>
<Table columns={columns} data={this.state.simulators} width='100%'/>
<ControlTable columns={columns} data={this.state.simulators} width='100%' onEdit={this.showEditModal} onDelete={this.showDeleteModal} />
<Button onClick={this.showModal}>New Simulator</Button>
<Button onClick={this.showNewModal}>New Simulator</Button>
<NewSimulatorDialog show={this.state.modal} onClose={this.closeModal}/>
<NewSimulatorDialog show={this.state.newModal} onClose={this.closeNewModal} />
<EditSimulatorDialog show={this.state.editModal} onClose={this.closeEditModal} simulator={this.state.modalSimulator} />
<Modal show={this.state.deleteModal}>
<Modal.Header>
<Modal.Title>Delete Simulator</Modal.Title>
</Modal.Header>
<Modal.Body>
Are you sure you want to delete the simulator <strong>'{this.state.modalSimulator.name}'</strong>?
</Modal.Body>
<Modal.Footer>
<Button onClick={this.cancelDeleteModal}>Cancel</Button>
<Button bsStyle="danger" onClick={this.confirmDeleteModal}>Delete</Button>
</Modal.Footer>
</Modal>
</div>
);
}

View file

@ -16,11 +16,11 @@ const SimulatorsDataManager = {
AppDispatcher.dispatch({
type: 'simulators/loaded',
simulators: response.simulators
}).catch(error => {
AppDispatcher.dispatch({
type: 'simulators/load-error',
error: error
});
});
}).catch(error => {
AppDispatcher.dispatch({
type: 'simulators/load-error',
error: error
});
});
},
@ -30,11 +30,39 @@ const SimulatorsDataManager = {
AppDispatcher.dispatch({
type: 'simulators/added',
simulator: response.simulator
}).catch(error => {
AppDispatcher.dispatch({
type: 'simulators/add-error',
error: error
});
});
}).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
});
});
}

View file

@ -22,6 +22,8 @@ class SimulatorStore extends ReduceStore {
}
reduce(state, action) {
var simulators;
switch (action.type) {
case 'simulators/start-load':
SimulatorsDataManager.loadSimulators();
@ -40,7 +42,7 @@ class SimulatorStore extends ReduceStore {
case 'simulators/added':
// state should always be immutable, thus make new copy
var simulators = state.slice();
simulators = state.slice();
simulators.push(action.simulator);
return simulators;
@ -49,6 +51,37 @@ class SimulatorStore extends ReduceStore {
// 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;
}

View file

@ -121,20 +121,14 @@ body {
/**
* Buttons
*/
/*button {
margin-top: 10px;
padding: 4px 8px;
.table-control-button {
border: none;
background-color: #527984;
color: #fff;
background: none;
font-size: 14px;
cursor: pointer;
padding: 0 5px;
}
button:hover {
background: #6EA2B0;
}*/
.table-control-button:hover {
color: #888;
}

View file

@ -1,8 +0,0 @@
/**
* File: projects.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.
**********************************************************************************/

View file

@ -1,8 +0,0 @@
/**
* File: simulators.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.
**********************************************************************************/