From 2fa75f0e58cee29ba906d1e8d253565b69006a6e Mon Sep 17 00:00:00 2001 From: Markus Grigull Date: Thu, 2 Mar 2017 16:22:57 +0100 Subject: [PATCH] Add delete and edit dialog to simulators --- src/api/rest-api.js | 24 +++ src/components/dialog-edit-simulator.js | 114 +++++++++++++ src/components/dialog-new-simulator.js | 162 +++++++++---------- src/components/table-control.js | 61 +++++++ src/containers/projects.js | 2 - src/containers/simulators.js | 105 ++++++++++-- src/data-managers/simulators-data-manager.js | 48 ++++-- src/stores/simulator-store.js | 35 +++- src/styles/app.css | 18 +-- src/styles/projects.css | 8 - src/styles/simulators.css | 8 - 11 files changed, 447 insertions(+), 138 deletions(-) create mode 100644 src/components/dialog-edit-simulator.js create mode 100644 src/components/table-control.js delete mode 100644 src/styles/projects.css delete mode 100644 src/styles/simulators.css diff --git a/src/api/rest-api.js b/src/api/rest-api.js index 0b3008c..bc886bb 100644 --- a/src/api/rest-api.js +++ b/src/api/rest-api.js @@ -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(); diff --git a/src/components/dialog-edit-simulator.js b/src/components/dialog-edit-simulator.js new file mode 100644 index 0000000..a281522 --- /dev/null +++ b/src/components/dialog-edit-simulator.js @@ -0,0 +1,114 @@ +/** + * File: dialog-new-simulator.js + * Author: Markus Grigull + * 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 ( + + + Edit Simulator + + + +
+ + Name + + + + Simulator ID + + + + Endpoint + + +
+
+ + + + + +
+ ); + } +} + +export default EditSimulatorDialog; diff --git a/src/components/dialog-new-simulator.js b/src/components/dialog-new-simulator.js index bce7065..95a3aa0 100644 --- a/src/components/dialog-new-simulator.js +++ b/src/components/dialog-new-simulator.js @@ -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 ( - - - New Simulator - + render() { + return ( + + + New Simulator + - -
- - Name - - - - Simulator ID - - - - Endpoint - - -
-
+ +
+ + Name + + + + Simulator ID + + + + Endpoint + + +
+
- - - - -
- ); - } - } + + + + +
+ ); + } +} - export default NewSimulatorDialog; +export default NewSimulatorDialog; diff --git a/src/components/table-control.js b/src/components/table-control.js new file mode 100644 index 0000000..9256a36 --- /dev/null +++ b/src/components/table-control.js @@ -0,0 +1,61 @@ +/** + * File: table.js + * Author: Markus Grigull + * 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 ( + + + + {this.props.columns.map(column => ( + + ))} + + + + + {rows.map((row) => ( + + {row.filter((element, index) => { + return index !== 0; + }).map((cell, index) => ( + + ))} + + + ))} + +
{column.title}
{cell} + + +
+ ); + } +} + +export default ControlTable; diff --git a/src/containers/projects.js b/src/containers/projects.js index bf87dbc..825ca7f 100644 --- a/src/containers/projects.js +++ b/src/containers/projects.js @@ -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 ]; diff --git a/src/containers/simulators.js b/src/containers/simulators.js index 03ecb04..d01ebf2 100644 --- a/src/containers/simulators.js +++ b/src/containers/simulators.js @@ -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 {

Simulators

- + - + - + + + + + + + Delete Simulator + + + + Are you sure you want to delete the simulator '{this.state.modalSimulator.name}'? + + + + + + + ); } diff --git a/src/data-managers/simulators-data-manager.js b/src/data-managers/simulators-data-manager.js index bba01a1..d10a333 100644 --- a/src/data-managers/simulators-data-manager.js +++ b/src/data-managers/simulators-data-manager.js @@ -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 }); }); } diff --git a/src/stores/simulator-store.js b/src/stores/simulator-store.js index 66285e1..83a4533 100644 --- a/src/stores/simulator-store.js +++ b/src/stores/simulator-store.js @@ -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; } diff --git a/src/styles/app.css b/src/styles/app.css index e3c697d..1230010 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -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; +} diff --git a/src/styles/projects.css b/src/styles/projects.css deleted file mode 100644 index 304b952..0000000 --- a/src/styles/projects.css +++ /dev/null @@ -1,8 +0,0 @@ -/** - * File: projects.css - * Author: Markus Grigull - * 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. - **********************************************************************************/ diff --git a/src/styles/simulators.css b/src/styles/simulators.css deleted file mode 100644 index 8cc54ed..0000000 --- a/src/styles/simulators.css +++ /dev/null @@ -1,8 +0,0 @@ -/** - * File: simulators.css - * Author: Markus Grigull - * 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. - **********************************************************************************/