From b79de99e9aa8ab2af5cbe731100552ba28ad4ab1 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sun, 22 Nov 2020 22:06:01 +0100 Subject: [PATCH 01/17] WIP: Show status of VILLASnode ICs #265 --- src/ic/ic-api-store.js | 49 ++++++++++++++++++++++++++++++++ src/ic/ic-data-data-manager.js | 18 ++++++++++++ src/ic/ic-dialog.js | 51 ++++++++++++++++++++++++++++++++-- src/ic/ics.js | 36 ++++++++++++++++++++---- 4 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 src/ic/ic-api-store.js diff --git a/src/ic/ic-api-store.js b/src/ic/ic-api-store.js new file mode 100644 index 0000000..d02d644 --- /dev/null +++ b/src/ic/ic-api-store.js @@ -0,0 +1,49 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import ArrayStore from '../common/array-store'; +import ICDataDataManager from './ic-data-data-manager'; + +class ICAPIStore extends ArrayStore { + constructor() { + super('ic-api', ICDataDataManager); + } + + + reduce(state, action) { + switch(action.type) { + + case 'ic-api/get-status': + ICDataDataManager.getStatus(action.url, action.socketname, action.token,action.icid); + return super.reduce(state, action); + + case 'ic-api/status-received': + let tempData = action.data; + tempData.icId = action.icid; + return this.updateElements(state, [tempData]); + + case 'ic-api/status-error': + console.log("status error"); + return super.reduce(state, action); + + default: + return super.reduce(state, action); + } + } +} + +export default new ICAPIStore(); diff --git a/src/ic/ic-data-data-manager.js b/src/ic/ic-data-data-manager.js index 0dcc853..5e10007 100644 --- a/src/ic/ic-data-data-manager.js +++ b/src/ic/ic-data-data-manager.js @@ -17,6 +17,7 @@ import WebsocketAPI from '../common/api/websocket-api'; import AppDispatcher from '../common/app-dispatcher'; +import RestAPI from "../common/api/rest-api"; const OFFSET_TYPE = 2; const OFFSET_VERSION = 4; @@ -43,6 +44,23 @@ class IcDataDataManager { } } + getStatus(url,socketname,token,icid){ + RestAPI.get(url, null).then(response => { + AppDispatcher.dispatch({ + type: 'ic-api/status-received', + data: response, + token: token, + socketname: socketname, + icid: icid, + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ic-api/status-error', + error: error + }) + }) + } + closeAll() { // close every open socket for (var identifier in this._sockets) { diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index b134f95..0a1a411 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -1,6 +1,9 @@ import React from 'react'; -import {FormLabel} from 'react-bootstrap'; +import {FormLabel, Button} from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; +import {Collapse} from 'react-collapse'; +import Icon from "../common/icon"; + class ICDialog extends React.Component { @@ -10,10 +13,20 @@ class ICDialog extends React.Component { super(props); this.state = { - ic: props.ic + timezone: false, + kernel: false, + system: false, }; } +/* static getDerivedStateFromProps(props, state){ + let icStatus = props.icStatus; + return { + icStatus: icStatus, + ic: props.ic, + }; + }*/ + onClose(canceled) { this.props.onClose(); } @@ -22,6 +35,19 @@ class ICDialog extends React.Component { } + showFurtherInfo(key){ + switch(key){ + case 'timezone': + this.setState({timezone: !this.state.timezone}); + return; + case 'kernel': + this.setState({kernel: !this.state.kernel}); + return; + case 'system': + this.setState({system: !this.state.system}); + return; + } + } render() { @@ -35,7 +61,26 @@ class ICDialog extends React.Component { size='lg' >
- Infos and Controls + Status + { + typeof this.props.icStatus !== "undefined" && Object.keys(this.props.icStatus).map(statusKey => ( + typeof this.props.icStatus[statusKey] === 'object' ? + (
+ + + { + Object.keys(this.props.icStatus[statusKey]).map(key => ( +
{key + ": " + this.props.icStatus[statusKey][key]}
+ )) + } +
+ +
) + : + (
{statusKey + ": " + this.props.icStatus[statusKey]}
) + )) + }
); diff --git a/src/ic/ics.js b/src/ic/ics.js index 138852f..2789b1e 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -24,6 +24,7 @@ import moment from 'moment' import AppDispatcher from '../common/app-dispatcher'; import InfrastructureComponentStore from './ic-store'; +import ICAPIStore from './ic-api-store'; import Icon from '../common/icon'; import Table from '../common/table'; @@ -38,7 +39,7 @@ import DeleteDialog from '../common/dialogs/delete-dialog'; class InfrastructureComponents extends Component { static getStores() { - return [ InfrastructureComponentStore ]; + return [ InfrastructureComponentStore, ICAPIStore ]; } static statePrio(state) { @@ -73,11 +74,15 @@ class InfrastructureComponents extends Component { return a.stateUpdatedAt < b.stateUpdatedAt; } }); + + const icInfo = ICAPIStore.getState(); return { sessionToken: localStorage.getItem("token"), ics: ics, + icInfo: icInfo, modalIC: {}, + modalICStatus: {}, deleteModal: false, icModal: false, selectedICs: [], @@ -90,11 +95,11 @@ class InfrastructureComponents extends Component { type: 'ics/start-load', token: this.state.sessionToken, }); - - // Start timer for periodic refresh + + // Start timer for periodic refresh this.timer = window.setInterval(() => this.refresh(), 10000); } - + componentWillUnmount() { window.clearInterval(this.timer); } @@ -109,6 +114,19 @@ class InfrastructureComponents extends Component { type: 'ics/start-load', token: this.state.sessionToken, }); + + this.state.ics.forEach(ic => { + if (ic.type === "villas-node" || ic.type === "villas-relay") { + let splitWebsocketURL = ic.websocketurl.split("/"); + AppDispatcher.dispatch({ + type: 'ic-api/get-status', + url: ic.apiurl + "/status", + socketname: splitWebsocketURL[splitWebsocketURL.length - 1], + token: this.state.sessionToken, + icid: ic.id, + }); + } + }) } } @@ -320,12 +338,18 @@ class InfrastructureComponents extends Component { let ic = this.state.ics.find(ic => ic.name === name); let index = this.state.ics.indexOf(ic); if(ic.type === "villas-node" || ic.type === "villas-relay"){ - return } + return } else{ return {name} } } + openICStatus(ic){ + let index = this.state.ics.indexOf(ic); + let icStatus = this.state.icInfo.find(info => info.icID === ic.id); + this.setState({ icModal: true, modalIC: ic, modalICStatus: icStatus, modalIndex: index }) + } + render() { const buttonStyle = { marginLeft: '10px' @@ -396,7 +420,7 @@ class InfrastructureComponents extends Component { this.closeNewModal(data)} /> this.closeEditModal(data)} ic={this.state.modalIC} /> this.closeImportModal(data)} /> - this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} /> + this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} /> this.closeDeleteModal(e)} /> From 0bc737349f123cf8707fadca1d7a1ac0a48c6bb1 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Fri, 27 Nov 2020 13:38:51 +0100 Subject: [PATCH 02/17] WIP: Show graph representing the current config #265 --- src/common/api/rest-api.js | 22 ++++++++++++++++++++++ src/ic/ic-api-store.js | 10 ++++++++++ src/ic/ic-data-data-manager.js | 16 ++++++++++++++++ src/ic/ics.js | 7 +++++++ 4 files changed, 55 insertions(+) diff --git a/src/common/api/rest-api.js b/src/common/api/rest-api.js index 084456c..50ff2de 100644 --- a/src/common/api/rest-api.js +++ b/src/common/api/rest-api.js @@ -170,6 +170,28 @@ class RestAPI { }); } + apiDownload(url, token) { + return new Promise(function (resolve, reject) { + var req = request.get(url).buffer(true).responseType("blob"); + + if (token != null) { + req.set('Authorization', "Bearer " + token); + } + + req.end(function (error, res) { + if (res == null || res.status !== 200) { + if (req.url !== prevURL) error.handled = isNetworkError(error); + prevURL = req.url; + reject(error); + } else { + let parts = url.split("/"); + resolve({data: res.body, type: res.type, id: parts[parts.length-1]}) + } + }); + }); + } + + } export default new RestAPI(); diff --git a/src/ic/ic-api-store.js b/src/ic/ic-api-store.js index d02d644..20d3816 100644 --- a/src/ic/ic-api-store.js +++ b/src/ic/ic-api-store.js @@ -40,6 +40,16 @@ class ICAPIStore extends ArrayStore { console.log("status error"); return super.reduce(state, action); + case 'ic-api/get-graph': + ICDataDataManager.getGraph(action.url, action.socketname, action.token); + return super.reduce(state, action); + + case 'ic-api/graph-received': + return super.reduce(state, action); + + case 'ic-api/graph-error': + return super.reduce(state, action); + default: return super.reduce(state, action); } diff --git a/src/ic/ic-data-data-manager.js b/src/ic/ic-data-data-manager.js index 5e10007..d82497a 100644 --- a/src/ic/ic-data-data-manager.js +++ b/src/ic/ic-data-data-manager.js @@ -61,6 +61,22 @@ class IcDataDataManager { }) } + getGraph(url,socketname,token){ + RestAPI.apiDownload(url, null).then(response => { + AppDispatcher.dispatch({ + type: 'ic-api/status-received', + data: response, + token: token, + socketname: socketname, + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ic-api/status-error', + error: error + }) + }) + } + closeAll() { // close every open socket for (var identifier in this._sockets) { diff --git a/src/ic/ics.js b/src/ic/ics.js index 2789b1e..a7024e8 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -125,6 +125,13 @@ class InfrastructureComponents extends Component { token: this.state.sessionToken, icid: ic.id, }); + + AppDispatcher.dispatch({ + type: 'ic-api/get-graph', + url: ic.apiurl + "/graph.svg", + socketname: splitWebsocketURL[splitWebsocketURL.length - 1], + token: this.state.sessionToken, + }); } }) } From d605d9c7bb6450425f1684c52c44dd1fd50c1b0a Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sat, 28 Nov 2020 16:44:58 +0100 Subject: [PATCH 03/17] Show status of VILLASnode ICs #265 --- src/ic/ic-dialog.js | 50 +++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 0a1a411..cdb48ad 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -13,20 +13,9 @@ class ICDialog extends React.Component { super(props); this.state = { - timezone: false, - kernel: false, - system: false, }; } -/* static getDerivedStateFromProps(props, state){ - let icStatus = props.icStatus; - return { - icStatus: icStatus, - ic: props.ic, - }; - }*/ - onClose(canceled) { this.props.onClose(); } @@ -36,17 +25,8 @@ class ICDialog extends React.Component { } showFurtherInfo(key){ - switch(key){ - case 'timezone': - this.setState({timezone: !this.state.timezone}); - return; - case 'kernel': - this.setState({kernel: !this.state.kernel}); - return; - case 'system': - this.setState({system: !this.state.system}); - return; - } + if(typeof this.state[key] === 'undefined') this.setState({[key]: false}); + this.setState({[key]: !this.state[key]}); } render() { @@ -68,13 +48,25 @@ class ICDialog extends React.Component { (
- - { - Object.keys(this.props.icStatus[statusKey]).map(key => ( -
{key + ": " + this.props.icStatus[statusKey][key]}
- )) - } -
+ + { + Object.keys(this.props.icStatus[statusKey]).map(key => ( + typeof this.props.icStatus[statusKey][key] === 'object' ? + (
+ + + + {Object.keys(this.props.icStatus[statusKey][key]).map(index => ( +
{index + ": " + this.props.icStatus[statusKey][key][index]}
+ ))} +
+
) + : + (
{key + ": " + this.props.icStatus[statusKey][key]}
) + )) + } +
) : From f88a75a972f2773f93d3ecce4a9285e47a7ebc0d Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sat, 28 Nov 2020 21:17:26 +0100 Subject: [PATCH 04/17] Show graph representing the current config #265 --- src/ic/ic-data-data-manager.js | 11 ++-- src/ic/ic-dialog.js | 17 +++++ src/ic/ic-graph-store.js | 62 +++++++++++++++++++ .../{ic-api-store.js => ic-status-store.js} | 24 +++---- src/ic/ics.js | 32 ++++++---- 5 files changed, 112 insertions(+), 34 deletions(-) create mode 100644 src/ic/ic-graph-store.js rename src/ic/{ic-api-store.js => ic-status-store.js} (70%) diff --git a/src/ic/ic-data-data-manager.js b/src/ic/ic-data-data-manager.js index d82497a..d0ca2fd 100644 --- a/src/ic/ic-data-data-manager.js +++ b/src/ic/ic-data-data-manager.js @@ -47,7 +47,7 @@ class IcDataDataManager { getStatus(url,socketname,token,icid){ RestAPI.get(url, null).then(response => { AppDispatcher.dispatch({ - type: 'ic-api/status-received', + type: 'ic-status/status-received', data: response, token: token, socketname: socketname, @@ -55,23 +55,24 @@ class IcDataDataManager { }); }).catch(error => { AppDispatcher.dispatch({ - type: 'ic-api/status-error', + type: 'ic-status/status-error', error: error }) }) } - getGraph(url,socketname,token){ + getGraph(url,socketname,token,icid){ RestAPI.apiDownload(url, null).then(response => { AppDispatcher.dispatch({ - type: 'ic-api/status-received', + type: 'ic-graph/graph-received', data: response, token: token, socketname: socketname, + icid: icid, }); }).catch(error => { AppDispatcher.dispatch({ - type: 'ic-api/status-error', + type: 'ic-graph/graph-error', error: error }) }) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index cdb48ad..12f65ec 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -29,7 +29,16 @@ class ICDialog extends React.Component { this.setState({[key]: !this.state[key]}); } + graphError(e){ + console.log("graph error"); + } + render() { + + let objectURL='' + if(typeof this.props.icGraph !== "undefined") { + objectURL = this.props.icGraph.objectURL + } return ( {statusKey + ": " + this.props.icStatus[statusKey]}) )) } +
Graph:
+
+ {objectURL !== '' ? ( + this.graphError(e)} alt={"Error"} src={objectURL} /> + ) : ( + Error + )} +
); diff --git a/src/ic/ic-graph-store.js b/src/ic/ic-graph-store.js new file mode 100644 index 0000000..cb44812 --- /dev/null +++ b/src/ic/ic-graph-store.js @@ -0,0 +1,62 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import ArrayStore from '../common/array-store'; +import ICDataDataManager from './ic-data-data-manager'; + +class ICGraphStore extends ArrayStore { + constructor() { + super('ic-graph', ICDataDataManager); + } + + saveGraph(state, action){ + + let icID = parseInt(action.icid); + const dublicate = state.some(element => element.icID === icID); + if(dublicate){ + return state + } + let icGraph = {}; + icGraph["icID"] = icID; + icGraph["data"] = new Blob([action.data.data], {type: action.data.type}); + icGraph["type"] = action.data.type; + icGraph["objectURL"] = URL.createObjectURL(icGraph["data"]); + + this.__emitChange(); + return this.updateElements(state, [icGraph]); + } + + reduce(state, action) { + switch(action.type) { + + case 'ic-graph/get-graph': + ICDataDataManager.getGraph(action.url, action.socketname, action.token, action.icid); + return super.reduce(state, action); + + case 'ic-graph/graph-received': + return this.saveGraph(state, action); + + case 'ic-graph/graph-error': + return super.reduce(state, action); + + default: + return super.reduce(state, action); + } + } +} + +export default new ICGraphStore(); diff --git a/src/ic/ic-api-store.js b/src/ic/ic-status-store.js similarity index 70% rename from src/ic/ic-api-store.js rename to src/ic/ic-status-store.js index 20d3816..c78353a 100644 --- a/src/ic/ic-api-store.js +++ b/src/ic/ic-status-store.js @@ -18,42 +18,32 @@ import ArrayStore from '../common/array-store'; import ICDataDataManager from './ic-data-data-manager'; -class ICAPIStore extends ArrayStore { +class ICStatusStore extends ArrayStore { constructor() { - super('ic-api', ICDataDataManager); + super('ic-status', ICDataDataManager); } reduce(state, action) { switch(action.type) { - case 'ic-api/get-status': + case 'ic-status/get-status': ICDataDataManager.getStatus(action.url, action.socketname, action.token,action.icid); return super.reduce(state, action); - case 'ic-api/status-received': + case 'ic-status/status-received': let tempData = action.data; - tempData.icId = action.icid; + tempData.icID = action.icid; return this.updateElements(state, [tempData]); - case 'ic-api/status-error': + case 'ic-status/status-error': console.log("status error"); return super.reduce(state, action); - case 'ic-api/get-graph': - ICDataDataManager.getGraph(action.url, action.socketname, action.token); - return super.reduce(state, action); - - case 'ic-api/graph-received': - return super.reduce(state, action); - - case 'ic-api/graph-error': - return super.reduce(state, action); - default: return super.reduce(state, action); } } } -export default new ICAPIStore(); +export default new ICStatusStore(); diff --git a/src/ic/ics.js b/src/ic/ics.js index a7024e8..f3ec9d3 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -24,7 +24,8 @@ import moment from 'moment' import AppDispatcher from '../common/app-dispatcher'; import InfrastructureComponentStore from './ic-store'; -import ICAPIStore from './ic-api-store'; +import ICStatusStore from './ic-status-store'; +import ICGraphStore from './ic-graph-store'; import Icon from '../common/icon'; import Table from '../common/table'; @@ -39,7 +40,7 @@ import DeleteDialog from '../common/dialogs/delete-dialog'; class InfrastructureComponents extends Component { static getStores() { - return [ InfrastructureComponentStore, ICAPIStore ]; + return [ InfrastructureComponentStore, ICStatusStore, ICGraphStore ]; } static statePrio(state) { @@ -75,14 +76,17 @@ class InfrastructureComponents extends Component { } }); - const icInfo = ICAPIStore.getState(); - + const icStatus = ICStatusStore.getState(); + const icGraph = ICGraphStore.getState(); + return { sessionToken: localStorage.getItem("token"), ics: ics, - icInfo: icInfo, + icStatus: icStatus, + icGraph: icGraph, modalIC: {}, modalICStatus: {}, + modalICGraph: {}, deleteModal: false, icModal: false, selectedICs: [], @@ -119,7 +123,7 @@ class InfrastructureComponents extends Component { if (ic.type === "villas-node" || ic.type === "villas-relay") { let splitWebsocketURL = ic.websocketurl.split("/"); AppDispatcher.dispatch({ - type: 'ic-api/get-status', + type: 'ic-status/get-status', url: ic.apiurl + "/status", socketname: splitWebsocketURL[splitWebsocketURL.length - 1], token: this.state.sessionToken, @@ -127,10 +131,11 @@ class InfrastructureComponents extends Component { }); AppDispatcher.dispatch({ - type: 'ic-api/get-graph', + type: 'ic-graph/get-graph', url: ic.apiurl + "/graph.svg", socketname: splitWebsocketURL[splitWebsocketURL.length - 1], token: this.state.sessionToken, + icid: ic.id, }); } }) @@ -343,18 +348,21 @@ class InfrastructureComponents extends Component { modifyNameColumn(name){ let ic = this.state.ics.find(ic => ic.name === name); - let index = this.state.ics.indexOf(ic); + if(ic.type === "villas-node" || ic.type === "villas-relay"){ - return } + return } else{ return {name} } } openICStatus(ic){ + let index = this.state.ics.indexOf(ic); - let icStatus = this.state.icInfo.find(info => info.icID === ic.id); - this.setState({ icModal: true, modalIC: ic, modalICStatus: icStatus, modalIndex: index }) + let icStatus = this.state.icStatus.find(status => status.icID === ic.id); + let icGraph = this.state.icGraph.find(graph => graph.icID === ic.id); + + this.setState({ icModal: true, modalIC: ic, modalICStatus: icStatus, modalICGraph: icGraph, modalIndex: index }) } render() { @@ -427,7 +435,7 @@ class InfrastructureComponents extends Component { this.closeNewModal(data)} /> this.closeEditModal(data)} ic={this.state.modalIC} /> this.closeImportModal(data)} /> - this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} /> + this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} icGraph={this.state.modalICGraph} /> this.closeDeleteModal(e)} /> From be0c656a22c3a67124bab3561ce665f3abb2fc6d Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sun, 29 Nov 2020 15:22:39 +0100 Subject: [PATCH 05/17] WIP: Send control commands from status dialog #265 --- src/ic/confirm-command.js | 48 +++++++++++++++++++++++++++++++++++++++ src/ic/ic-dialog.js | 20 ++++++++++++++++ src/ic/ics.js | 6 ++++- 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/ic/confirm-command.js diff --git a/src/ic/confirm-command.js b/src/ic/confirm-command.js new file mode 100644 index 0000000..43b6885 --- /dev/null +++ b/src/ic/confirm-command.js @@ -0,0 +1,48 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React from 'react'; +import { Button, Modal} from 'react-bootstrap'; + +class ConfirmCommand extends React.Component { + onModalKeyPress = (event) => { + if (event.key === 'Enter') { + event.preventDefault(); + + this.props.onClose(false); + } + } + + render() { + return this.props.onClose(false)} onKeyPress={this.onModalKeyPress}> + + Confirm {this.props.command} + + + + Are you sure you want to {this.props.command} '{this.props.name}'? + + + + + + + ; + } +} + +export default ConfirmCommand; diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 12f65ec..0acbcb5 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -3,6 +3,7 @@ import {FormLabel, Button} from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; import {Collapse} from 'react-collapse'; import Icon from "../common/icon"; +import ConfirmCommand from './confirm-command'; @@ -13,6 +14,8 @@ class ICDialog extends React.Component { super(props); this.state = { + confirmCommand: false, + command: '', }; } @@ -33,6 +36,15 @@ class ICDialog extends React.Component { console.log("graph error"); } + closeConfirmModal(canceled){ + if(!canceled){ + this.props.sendControlCommand(this.state.command); + } + + this.setState({confirmCommand: false, command: ''}); + } + + render() { let objectURL='' @@ -91,7 +103,15 @@ class ICDialog extends React.Component { )} + +
Controls
+ + + + this.closeConfirmModal(c)} /> + + ); } } diff --git a/src/ic/ics.js b/src/ic/ics.js index f3ec9d3..c582503 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -365,6 +365,10 @@ class InfrastructureComponents extends Component { this.setState({ icModal: true, modalIC: ic, modalICStatus: icStatus, modalICGraph: icGraph, modalIndex: index }) } + sendControlCommand(command){ + console.log(command); + } + render() { const buttonStyle = { marginLeft: '10px' @@ -435,7 +439,7 @@ class InfrastructureComponents extends Component { this.closeNewModal(data)} /> this.closeEditModal(data)} ic={this.state.modalIC} /> this.closeImportModal(data)} /> - this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} icGraph={this.state.modalICGraph} /> + this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} icGraph={this.state.modalICGraph} sendControlCommand={(command) => this.sendControlCommand(command)}/> this.closeDeleteModal(e)} /> From b24f5cf638f16fd1550dcfa4b0e4dee3b56c5018 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sun, 6 Dec 2020 16:06:15 +0100 Subject: [PATCH 06/17] Send IC control commands from status dialog #265 --- src/ic/ic-data-data-manager.js | 34 ++++++++++++++++++++++++++++++++++ src/ic/ic-dialog.js | 2 +- src/ic/ic-status-store.js | 26 ++++++++++++++++++++++++-- src/ic/ics.js | 23 ++++++++++++++++++++--- 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/src/ic/ic-data-data-manager.js b/src/ic/ic-data-data-manager.js index d0ca2fd..b26675c 100644 --- a/src/ic/ic-data-data-manager.js +++ b/src/ic/ic-data-data-manager.js @@ -78,6 +78,40 @@ class IcDataDataManager { }) } + restart(url,socketname,token){ + RestAPI.post(url, null).then(response => { + AppDispatcher.dispatch({ + type: 'ic-status/restart-successful', + data: response, + token: token, + socketname: socketname, + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ic-status/restart-error', + error: error + }) + }) + } + + shutdown(url,socketname,token){ + RestAPI.post(url, null).then(response => { + AppDispatcher.dispatch({ + type: 'ic-status/shutdown-successful', + data: response, + token: token, + socketname: socketname, + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ic-status/shutdown-error', + error: error + }) + }) + } + + + closeAll() { // close every open socket for (var identifier in this._sockets) { diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 0acbcb5..4e0e9a4 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -38,7 +38,7 @@ class ICDialog extends React.Component { closeConfirmModal(canceled){ if(!canceled){ - this.props.sendControlCommand(this.state.command); + this.props.sendControlCommand(this.state.command,this.props.ic); } this.setState({confirmCommand: false, command: ''}); diff --git a/src/ic/ic-status-store.js b/src/ic/ic-status-store.js index c78353a..3f701ef 100644 --- a/src/ic/ic-status-store.js +++ b/src/ic/ic-status-store.js @@ -28,7 +28,7 @@ class ICStatusStore extends ArrayStore { switch(action.type) { case 'ic-status/get-status': - ICDataDataManager.getStatus(action.url, action.socketname, action.token,action.icid); + ICDataDataManager.getStatus(action.url, action.socketname, action.token, action.icid); return super.reduce(state, action); case 'ic-status/status-received': @@ -38,7 +38,29 @@ class ICStatusStore extends ArrayStore { case 'ic-status/status-error': console.log("status error"); - return super.reduce(state, action); + return state; + + case 'ic-status/restart': + ICDataDataManager.restart(action.url, action.socketname, action.token); + return state; + + case 'ic-status/restart-successful': + return state; + + case 'ic-status/restart-error': + console.log("restart error"); + return state; + + case 'ic-status/shutdown': + ICDataDataManager.shutdown(action.url, action.socketname, action.token); + return state; + + case 'ic-status/shutdown-successful': + return state; + + case 'ic-status/shutdown-error': + console.log("shutdown error"); + return state; default: return super.reduce(state, action); diff --git a/src/ic/ics.js b/src/ic/ics.js index c582503..4f8e2eb 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -365,8 +365,25 @@ class InfrastructureComponents extends Component { this.setState({ icModal: true, modalIC: ic, modalICStatus: icStatus, modalICGraph: icGraph, modalIndex: index }) } - sendControlCommand(command){ - console.log(command); + sendControlCommand(command,ic){ + let splitWebsocketURL = ic.websocketurl.split("/"); + + if(command === "restart"){ + AppDispatcher.dispatch({ + type: 'ic-status/restart', + url: ic.apiurl + "/restart", + socketname: splitWebsocketURL[splitWebsocketURL.length - 1], + token: this.state.sessionToken, + }); + }else if(command === "shutdown"){ + AppDispatcher.dispatch({ + type: 'ic-status/shutdown', + url: ic.apiurl + "/shutdown", + socketname: splitWebsocketURL[splitWebsocketURL.length - 1], + token: this.state.sessionToken, + }); + } + } render() { @@ -439,7 +456,7 @@ class InfrastructureComponents extends Component { this.closeNewModal(data)} /> this.closeEditModal(data)} ic={this.state.modalIC} /> this.closeImportModal(data)} /> - this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} icGraph={this.state.modalICGraph} sendControlCommand={(command) => this.sendControlCommand(command)}/> + this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} icGraph={this.state.modalICGraph} sendControlCommand={(command, ic) => this.sendControlCommand(command, ic)}/> this.closeDeleteModal(e)} /> From ba81bf14e6e88f567fdc6d01ce827e05b59f6d03 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sat, 12 Dec 2020 17:31:22 +0100 Subject: [PATCH 07/17] IC status and graph now load as soon as ICs are loaded #265 --- src/ic/ic-store.js | 21 +++++++++++++++++++++ src/ic/ics.js | 20 -------------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index d73e555..78e90ac 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -19,6 +19,7 @@ import ArrayStore from '../common/array-store'; import ICsDataManager from './ics-data-manager'; import ICDataDataManager from './ic-data-data-manager'; import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; +import AppDispatcher from '../common/app-dispatcher'; class InfrastructureComponentStore extends ArrayStore { constructor() { @@ -28,6 +29,26 @@ class InfrastructureComponentStore extends ArrayStore { reduce(state, action) { switch(action.type) { case 'ics/loaded': + action.data.forEach(ic => { + if (ic.type === "villas-node" || ic.type === "villas-relay") { + let splitWebsocketURL = ic.websocketurl.split("/"); + AppDispatcher.dispatch({ + type: 'ic-status/get-status', + url: ic.apiurl + "/status", + socketname: splitWebsocketURL[splitWebsocketURL.length - 1], + token: action.token, + icid: ic.id, + }); + + AppDispatcher.dispatch({ + type: 'ic-graph/get-graph', + url: ic.apiurl + "/graph.svg", + socketname: splitWebsocketURL[splitWebsocketURL.length - 1], + token: action.token, + icid: ic.id, + }); + } + }) return super.reduce(state, action); diff --git a/src/ic/ics.js b/src/ic/ics.js index 4f8e2eb..fed6de5 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -119,26 +119,6 @@ class InfrastructureComponents extends Component { token: this.state.sessionToken, }); - this.state.ics.forEach(ic => { - if (ic.type === "villas-node" || ic.type === "villas-relay") { - let splitWebsocketURL = ic.websocketurl.split("/"); - AppDispatcher.dispatch({ - type: 'ic-status/get-status', - url: ic.apiurl + "/status", - socketname: splitWebsocketURL[splitWebsocketURL.length - 1], - token: this.state.sessionToken, - icid: ic.id, - }); - - AppDispatcher.dispatch({ - type: 'ic-graph/get-graph', - url: ic.apiurl + "/graph.svg", - socketname: splitWebsocketURL[splitWebsocketURL.length - 1], - token: this.state.sessionToken, - icid: ic.id, - }); - } - }) } } From 6d59f83002cefaf79ed857652c610cdfc0876111 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sat, 12 Dec 2020 20:08:22 +0100 Subject: [PATCH 08/17] Format IC dialog window #265 --- src/ic/ic-dialog.js | 51 ++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 4e0e9a4..9b29d9c 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -1,5 +1,5 @@ import React from 'react'; -import {FormLabel, Button} from 'react-bootstrap'; +import {Button, Row, Col} from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; import {Collapse} from 'react-collapse'; import Icon from "../common/icon"; @@ -47,6 +47,9 @@ class ICDialog extends React.Component { render() { + let icStatus = this.props.icStatus; + delete icStatus['icID']; + let objectURL='' if(typeof this.props.icGraph !== "undefined") { objectURL = this.props.icGraph.objectURL @@ -55,46 +58,52 @@ class ICDialog extends React.Component { return ( this.onClose(c)} valid={true} - size='lg' + size='xl' + blendOutCancel = {true} >
- Status + + +
Status:
{ - typeof this.props.icStatus !== "undefined" && Object.keys(this.props.icStatus).map(statusKey => ( - typeof this.props.icStatus[statusKey] === 'object' ? + typeof icStatus !== "undefined" && Object.keys(icStatus).map(statusKey => ( + typeof icStatus[statusKey] === 'object' ? (
{ - Object.keys(this.props.icStatus[statusKey]).map(key => ( - typeof this.props.icStatus[statusKey][key] === 'object' ? + Object.keys(icStatus[statusKey]).map(key => ( + typeof icStatus[statusKey][key] === 'object' ? (
- {Object.keys(this.props.icStatus[statusKey][key]).map(index => ( -
{index + ": " + this.props.icStatus[statusKey][key][index]}
+ {Object.keys(icStatus[statusKey][key]).map(index => ( +
{index + ": " + icStatus[statusKey][key][index]}
))}
) : - (
{key + ": " + this.props.icStatus[statusKey][key]}
) + (
{key + ": " + icStatus[statusKey][key]}
) )) }
) : - (
{statusKey + ": " + this.props.icStatus[statusKey]}
) + (
{statusKey + ": " + icStatus[statusKey]}
) )) } -
Graph:
+ + + +
Graph:
{objectURL !== '' ? ( this.graphError(e)} alt={"Error"} src={objectURL} /> @@ -102,14 +111,18 @@ class ICDialog extends React.Component { Error )}
- -
Controls
- - + +
Controls:
+
+ + +
this.closeConfirmModal(c)} /> - + +
+
); From cbec6fe88a014712b1b1e6bd88b3d30d0a570df9 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Tue, 29 Dec 2020 16:36:25 +0100 Subject: [PATCH 09/17] solve warning and error --- src/ic/ic-dialog.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 9b29d9c..6e225a5 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -16,9 +16,18 @@ class ICDialog extends React.Component { this.state = { confirmCommand: false, command: '', + icStatus: {} }; } + static getDerivedStateFromProps(props, state){ + if(typeof props.icStatus !== 'undefined'){ + return {icStatus: props.icStatus} + } else { + return {} + } + } + onClose(canceled) { this.props.onClose(); } @@ -47,7 +56,7 @@ class ICDialog extends React.Component { render() { - let icStatus = this.props.icStatus; + let icStatus = this.state.icStatus; delete icStatus['icID']; let objectURL='' @@ -72,32 +81,32 @@ class ICDialog extends React.Component { { typeof icStatus !== "undefined" && Object.keys(icStatus).map(statusKey => ( typeof icStatus[statusKey] === 'object' ? - (
+ (
{ Object.keys(icStatus[statusKey]).map(key => ( typeof icStatus[statusKey][key] === 'object' ? - (
+ (
{Object.keys(icStatus[statusKey][key]).map(index => ( -
{index + ": " + icStatus[statusKey][key][index]}
+
{index + ": " + icStatus[statusKey][key][index]}
))}
) : - (
{key + ": " + icStatus[statusKey][key]}
) + (
{key + ": " + icStatus[statusKey][key]}
) )) }
) : - (
{statusKey + ": " + icStatus[statusKey]}
) + (
{statusKey + ": " + icStatus[statusKey]}
) )) } From 3a5d828d344ae58729c4fe0772ebe08fbcd83c8b Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 5 Jan 2021 12:03:35 +0100 Subject: [PATCH 10/17] update package-lock --- package-lock.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 745cbea..4479160 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3087,7 +3087,7 @@ }, "asynckit": { "version": "0.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "at-least-node": { @@ -4540,7 +4540,7 @@ }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cosmiconfig": { @@ -5234,7 +5234,7 @@ }, "delayed-stream": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { @@ -5575,7 +5575,7 @@ }, "encoding": { "version": "0.1.12", - "resolved": false, + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { "iconv-lite": "~0.4.13" @@ -8071,9 +8071,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "internal-ip": { "version": "4.3.0", @@ -11097,7 +11097,7 @@ }, "methods": { "version": "1.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, "microevent.ts": { @@ -11865,7 +11865,7 @@ }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { @@ -12308,7 +12308,7 @@ }, "performance-now": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { @@ -14416,7 +14416,7 @@ }, "react-textarea-autosize": { "version": "6.1.0", - "resolved": "http://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-6.1.0.tgz", "integrity": "sha512-F6bI1dgib6fSvG8so1HuArPUv+iVEfPliuLWusLF+gAKz0FbB4jLrWUrTAeq1afnPT2c9toEZYUdz/y1uKMy4A==", "requires": { "prop-types": "^15.6.0" @@ -17161,7 +17161,7 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util.promisify": { From d4ec861103628e463234c00953ee08adf1b9852e Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 5 Jan 2021 15:54:08 +0100 Subject: [PATCH 11/17] Add TODO for VILLASnode status updates --- src/ic/ic-status-store.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ic/ic-status-store.js b/src/ic/ic-status-store.js index 3f701ef..62d6d08 100644 --- a/src/ic/ic-status-store.js +++ b/src/ic/ic-status-store.js @@ -34,6 +34,10 @@ class ICStatusStore extends ArrayStore { case 'ic-status/status-received': let tempData = action.data; tempData.icID = action.icid; + + // TODO: edit state (e.g. running) of IC according to received state (only for ICs that are NOT managed externally) + // TODO: playback state info to backend using start-edit dispatch for IC + return this.updateElements(state, [tempData]); case 'ic-status/status-error': From 95f47a3557c01a568ac69bd7e4e9c23ca3a58a8a Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sun, 10 Jan 2021 19:04:47 +0100 Subject: [PATCH 12/17] IC control buttons only available for admins #265 --- src/ic/ic-dialog.js | 5 ++++- src/ic/ics.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 6e225a5..68276e7 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -121,12 +121,15 @@ class ICDialog extends React.Component { )}
- + {this.props.userRole === "Admin"? ( +
Controls:
+
) + : (
) } this.closeConfirmModal(c)} /> diff --git a/src/ic/ics.js b/src/ic/ics.js index aa0fffa..a1e494c 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -436,7 +436,7 @@ class InfrastructureComponents extends Component { this.closeNewModal(data)} /> this.closeEditModal(data)} ic={this.state.modalIC} /> this.closeImportModal(data)} /> - this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} icStatus={this.state.modalICStatus} icGraph={this.state.modalICGraph} sendControlCommand={(command, ic) => this.sendControlCommand(command, ic)}/> + this.closeICModal(data)} ic={this.state.modalIC} token={this.state.sessionToken} userRole={this.state.currentUser.role} icStatus={this.state.modalICStatus} icGraph={this.state.modalICGraph} sendControlCommand={(command, ic) => this.sendControlCommand(command, ic)}/> this.closeDeleteModal(e)} />
From 3e74e0886164ff0d5dbec70001b23ddd475280ff Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sun, 17 Jan 2021 16:06:13 +0100 Subject: [PATCH 13/17] Reformat IC status list --- src/ic/ic-dialog.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 68276e7..33cb9e5 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -63,6 +63,11 @@ class ICDialog extends React.Component { if(typeof this.props.icGraph !== "undefined") { objectURL = this.props.icGraph.objectURL } + + let spanStyle = { + display: 'inline-block', + width: '130px' + } return ( ( typeof icStatus[statusKey] === 'object' ? (
- { @@ -94,19 +99,19 @@ class ICDialog extends React.Component { {Object.keys(icStatus[statusKey][key]).map(index => ( -
{index + ": " + icStatus[statusKey][key][index]}
+
{index + ":"}{icStatus[statusKey][key][index]}
))}
) : - (
{key + ": " + icStatus[statusKey][key]}
) + (
{key + ":"}{icStatus[statusKey][key]}
) )) } ) : - (
{statusKey + ": " + icStatus[statusKey]}
) + (
{statusKey + ":"}{icStatus[statusKey]}
) )) } From 8edeb4b04c4dc0a64517d1a2612566f848439572 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sun, 17 Jan 2021 18:47:08 +0100 Subject: [PATCH 14/17] edit state of IC according to received state #265 --- src/ic/ic-data-data-manager.js | 12 +++++++++++- src/ic/ic-status-store.js | 2 +- src/ic/ic-store.js | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ic/ic-data-data-manager.js b/src/ic/ic-data-data-manager.js index b26675c..087b294 100644 --- a/src/ic/ic-data-data-manager.js +++ b/src/ic/ic-data-data-manager.js @@ -44,15 +44,25 @@ class IcDataDataManager { } } - getStatus(url,socketname,token,icid){ + getStatus(url,socketname,token,icid,ic){ RestAPI.get(url, null).then(response => { + let tempIC = ic; + tempIC.state = response.state; AppDispatcher.dispatch({ type: 'ic-status/status-received', data: response, token: token, socketname: socketname, icid: icid, + ic: ic }); + if(!ic.managedexternally){ + AppDispatcher.dispatch({ + type: 'ics/start-edit', + data: tempIC, + token: token, + }); + } }).catch(error => { AppDispatcher.dispatch({ type: 'ic-status/status-error', diff --git a/src/ic/ic-status-store.js b/src/ic/ic-status-store.js index 62d6d08..36526c6 100644 --- a/src/ic/ic-status-store.js +++ b/src/ic/ic-status-store.js @@ -28,7 +28,7 @@ class ICStatusStore extends ArrayStore { switch(action.type) { case 'ic-status/get-status': - ICDataDataManager.getStatus(action.url, action.socketname, action.token, action.icid); + ICDataDataManager.getStatus(action.url, action.socketname, action.token, action.icid, action.ic); return super.reduce(state, action); case 'ic-status/status-received': diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index 78e90ac..acc6c1e 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -38,6 +38,7 @@ class InfrastructureComponentStore extends ArrayStore { socketname: splitWebsocketURL[splitWebsocketURL.length - 1], token: action.token, icid: ic.id, + ic: ic }); AppDispatcher.dispatch({ From ddc9da537c64dda5d307bae38904116b79e9eefb Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Fri, 22 Jan 2021 18:22:25 +0100 Subject: [PATCH 15/17] Use JsonView to display status #265 --- src/ic/ic-dialog.js | 99 +++++++++++++++------------------------ src/ic/ic-status-store.js | 3 -- 2 files changed, 39 insertions(+), 63 deletions(-) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index 33cb9e5..bdd4488 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -1,9 +1,9 @@ import React from 'react'; import {Button, Row, Col} from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; -import {Collapse} from 'react-collapse'; import Icon from "../common/icon"; import ConfirmCommand from './confirm-command'; +import JsonView from 'react-json-view'; @@ -72,76 +72,55 @@ class ICDialog extends React.Component { return ( this.onClose(c)} valid={true} size='xl' - blendOutCancel = {true} + blendOutCancel={true} >
- - -
Status:
- { - typeof icStatus !== "undefined" && Object.keys(icStatus).map(statusKey => ( - typeof icStatus[statusKey] === 'object' ? - (
- - - { - Object.keys(icStatus[statusKey]).map(key => ( - typeof icStatus[statusKey][key] === 'object' ? - (
- - + + +
Status:
- {Object.keys(icStatus[statusKey][key]).map(index => ( -
{index + ":"}{icStatus[statusKey][key][index]}
- ))} -
-
) - : - (
{key + ":"}{icStatus[statusKey][key]}
) - )) - } -
+ -
) - : - (
{statusKey + ":"}{icStatus[statusKey]}
) - )) - } - - - -
Graph:
-
- {objectURL !== '' ? ( - this.graphError(e)} alt={"Error"} src={objectURL} /> - ) : ( - Error - )} -
- - {this.props.userRole === "Admin"? ( -
-
Controls:
-
- - -
-
) - : (
) } + - this.closeConfirmModal(c)} /> - -
+ +
Graph:
+
+ {objectURL !== '' ? ( + this.graphError(e)} alt={"Error"} src={objectURL} /> + ) : ( + Error + )} +
+ + {this.props.userRole === "Admin" ? ( +
+
Controls:
+
+ + +
+
) + : (
)} + + this.closeConfirmModal(c)} /> + +
- + ); } } diff --git a/src/ic/ic-status-store.js b/src/ic/ic-status-store.js index 36526c6..4895a8d 100644 --- a/src/ic/ic-status-store.js +++ b/src/ic/ic-status-store.js @@ -35,9 +35,6 @@ class ICStatusStore extends ArrayStore { let tempData = action.data; tempData.icID = action.icid; - // TODO: edit state (e.g. running) of IC according to received state (only for ICs that are NOT managed externally) - // TODO: playback state info to backend using start-edit dispatch for IC - return this.updateElements(state, [tempData]); case 'ic-status/status-error': From 0405ec82da263e64485f119a48d46790be770bb1 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Sun, 24 Jan 2021 16:43:19 +0100 Subject: [PATCH 16/17] make graph downloadable #265 --- src/ic/ic-dialog.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ic/ic-dialog.js b/src/ic/ic-dialog.js index bdd4488..591db53 100644 --- a/src/ic/ic-dialog.js +++ b/src/ic/ic-dialog.js @@ -4,7 +4,7 @@ import Dialog from '../common/dialogs/dialog'; import Icon from "../common/icon"; import ConfirmCommand from './confirm-command'; import JsonView from 'react-json-view'; - +import FileSaver from 'file-saver'; class ICDialog extends React.Component { @@ -53,6 +53,10 @@ class ICDialog extends React.Component { this.setState({confirmCommand: false, command: ''}); } + downloadGraph(url){ + FileSaver.saveAs(url, this.props.ic.name + ".svg"); +} + render() { @@ -63,11 +67,6 @@ class ICDialog extends React.Component { if(typeof this.props.icGraph !== "undefined") { objectURL = this.props.icGraph.objectURL } - - let spanStyle = { - display: 'inline-block', - width: '130px' - } return ( +
+ +
Graph:
{objectURL !== '' ? ( From bfed3e231bac38f4aae3797762949ac733ce0b35 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Mon, 25 Jan 2021 10:30:46 +0100 Subject: [PATCH 17/17] fix bug in outdated computation; show no icon if IC is not managed via AMQP --- src/ic/ics.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ic/ics.js b/src/ic/ics.js index a1e494c..b96cf89 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -75,10 +75,10 @@ class InfrastructureComponents extends Component { return a.stateUpdatedAt < b.stateUpdatedAt; } }); - + const icStatus = ICStatusStore.getState(); const icGraph = ICGraphStore.getState(); - + return { sessionToken: localStorage.getItem("token"), ics: ics, @@ -99,11 +99,11 @@ class InfrastructureComponents extends Component { type: 'ics/start-load', token: this.state.sessionToken, }); - + // Start timer for periodic refresh this.timer = window.setInterval(() => this.refresh(), 10000); } - + componentWillUnmount() { window.clearInterval(this.timer); } @@ -228,12 +228,12 @@ class InfrastructureComponents extends Component { } static isICOutdated(component) { - if (!component.stateUpdatedAt) + if (!component.stateUpdateAt) return true; const fiveMinutes = 5 * 60 * 1000; - return Date.now() - new Date(component.stateUpdatedAt) > fiveMinutes; + return Date.now() - new Date(component.stateUpdateAt) > fiveMinutes; } stateLabelStyle(state, component){ @@ -312,7 +312,7 @@ class InfrastructureComponents extends Component { if(managedExternally){ return } else { - return + return "" } } @@ -328,7 +328,7 @@ class InfrastructureComponents extends Component { modifyNameColumn(name){ let ic = this.state.ics.find(ic => ic.name === name); - + if(ic.type === "villas-node" || ic.type === "villas-relay"){ return } else{ @@ -337,17 +337,17 @@ class InfrastructureComponents extends Component { } openICStatus(ic){ - + let index = this.state.ics.indexOf(ic); let icStatus = this.state.icStatus.find(status => status.icID === ic.id); let icGraph = this.state.icGraph.find(graph => graph.icID === ic.id); - + this.setState({ icModal: true, modalIC: ic, modalICStatus: icStatus, modalICGraph: icGraph, modalIndex: index }) } sendControlCommand(command,ic){ let splitWebsocketURL = ic.websocketurl.split("/"); - + if(command === "restart"){ AppDispatcher.dispatch({ type: 'ic-status/restart',