From 0fde0d95813e494287559143cecaedd669e9b39d Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Tue, 13 Apr 2021 19:55:48 +0200 Subject: [PATCH 01/25] ICs clean up: delete unnecessary code --- src/ic/ics.js | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/ic/ics.js b/src/ic/ics.js index 7698317..fe202e6 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -201,9 +201,6 @@ class InfrastructureComponents extends Component { } } - closeICModal(data){ - this.setState({ icModal : false }); - } closeDeleteModal(confirmDelete){ this.setState({ deleteModal: false }); @@ -345,14 +342,6 @@ class InfrastructureComponents extends Component { return dateTime.fromNow() } - modifyManagedExternallyColumn(managedExternally, component){ - if(managedExternally){ - return - } else { - return "" - } - } - modifyUptimeColumn(uptime, component){ if(uptime >= 0){ let momentDurationFormatSetup = require("moment-duration-format"); @@ -366,11 +355,6 @@ class InfrastructureComponents extends Component { } } - openICStatus(ic){ - let index = this.state.ics.indexOf(ic); - this.setState({ icModal: true, modalIC: ic, modalIndex: index }) - } - isLocalIC(index, ics){ let ic = ics[index] return !ic.managedexternally @@ -451,14 +435,6 @@ class InfrastructureComponents extends Component { render() { - const buttonStyle = { - marginLeft: '10px' - }; - - const iconStyle = { - height: '30px', - width: '30px' - } let managerTable = this.getICCategoryTable(this.state.managers, false, "IC Managers") let simulatorTable = this.getICCategoryTable(this.state.simulators, true, "Simulators") From fb6f4f2b973f193aec9c97f49450be37c639eab0 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Wed, 21 Apr 2021 21:20:22 +0200 Subject: [PATCH 02/25] WIP: IC dialog customization for VILLASnode #303 --- src/ic/ic-store.js | 21 +++++++++++++++++++-- src/ic/ics-data-manager.js | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index bc9aa18..f3532e0 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -112,9 +112,18 @@ class InfrastructureComponentStore extends ArrayStore { ICsDataManager.getStatus(action.url, action.token, action.ic); return super.reduce(state, action); + case 'ics/get-config': + ICsDataManager.getConfig(action.url, action.token, action.ic); + return super.reduce(state, action); + + case 'ics/get-statistics': + ICsDataManager.getStatistics(action.url, action.token, action.ic); + return super.reduce(state, action); + + case 'ics/status-received': let tempIC = action.ic; - if(!tempIC.managedexternally){ + if (!tempIC.managedexternally) { tempIC.state = action.data.state; tempIC.uptime = action.data.time_now - action.data.time_started; tempIC.statusupdateraw = action.data @@ -130,9 +139,17 @@ class InfrastructureComponentStore extends ArrayStore { console.log("status error:", action.error); return super.reduce(state, action); + case 'ics/config-error': + console.log("config error:", action.error); + return super.reduce(state, action); + + case 'ics/statistics-error': + console.log("statistics error:", action.error); + return super.reduce(state, action); + case 'ics/nodestats-received': let tempIC2 = action.ic; - if(!tempIC2.managedexternally){ + if (!tempIC2.managedexternally) { if (tempIC2.statusupdateraw === null || tempIC2.statusupdateraw === undefined) { tempIC2.statusupdateraw = {}; } diff --git a/src/ic/ics-data-manager.js b/src/ic/ics-data-manager.js index 74b4080..43dc045 100644 --- a/src/ic/ics-data-manager.js +++ b/src/ic/ics-data-manager.js @@ -117,7 +117,8 @@ class IcsDataManager extends RestDataManager { }) // get name of websocket - /*let ws_api = ic.websocketurl.split("/") + /* + let ws_api = ic.websocketurl.split("/") let ws_name = ws_api[ws_api.length-1] // websocket name is the last element in the websocket url RestAPI.get(url + "/node/" + ws_name + "/stats", null).then(response => { @@ -136,6 +137,38 @@ class IcsDataManager extends RestDataManager { } + getConfig(url,token,ic){ + RestAPI.get(url + "node/" + ic.uuid, null).then(response => { + AppDispatcher.dispatch({ + type: 'ics/config-received', + data: response, + token: token, + ic: ic + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ics/config-error', + error: error + }) + }) + } + + getStatistics(url,token,ic){ + RestAPI.get(url + "/node/" +ic.uuid + "/stats", null).then(response => { + AppDispatcher.dispatch({ + type: 'ics/statistics-received', + data: response, + token: token, + ic: ic + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ics/statistics-error', + error: error + }) + }) + } + restart(url,token){ RestAPI.post(url, null).then(response => { AppDispatcher.dispatch({ From acde44528fad360e516bccd36ba65b99fb8b54f2 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 28 Apr 2021 11:47:31 +0200 Subject: [PATCH 03/25] cascade requests of status, config and statistics of VILLASnode so that IC raw status does not get overwritten; handle bad request response of statistics request separately --- package-lock.json | 3 ++- src/ic/ic-store.js | 49 +++++++++++++++++++++++++------------- src/ic/ics-data-manager.js | 43 +++++++++++++++------------------ 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/package-lock.json b/package-lock.json index c9207a8..8d7c22d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17825,7 +17825,8 @@ }, "ssri": { "version": "6.0.1", - "resolved": "", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "requires": { "figgy-pudding": "^3.5.1" } diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index f3532e0..385af58 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -112,15 +112,6 @@ class InfrastructureComponentStore extends ArrayStore { ICsDataManager.getStatus(action.url, action.token, action.ic); return super.reduce(state, action); - case 'ics/get-config': - ICsDataManager.getConfig(action.url, action.token, action.ic); - return super.reduce(state, action); - - case 'ics/get-statistics': - ICsDataManager.getStatistics(action.url, action.token, action.ic); - return super.reduce(state, action); - - case 'ics/status-received': let tempIC = action.ic; if (!tempIC.managedexternally) { @@ -132,6 +123,8 @@ class InfrastructureComponentStore extends ArrayStore { data: tempIC, token: action.token, }); + + ICsDataManager.getConfig(action.url, action.token, tempIC); } return super.reduce(state, action); @@ -143,11 +136,39 @@ class InfrastructureComponentStore extends ArrayStore { console.log("config error:", action.error); return super.reduce(state, action); - case 'ics/statistics-error': - console.log("statistics error:", action.error); + case 'ics/config-received': + let temp = action.ic; + if (!temp.managedexternally) { + if (temp.statusupdateraw === null || temp.statusupdateraw === undefined) { + temp.statusupdateraw = {}; + } + temp.statusupdateraw["config"] = action.data; + AppDispatcher.dispatch({ + type: 'ics/start-edit', + data: temp, + token: action.token, + }); + ICsDataManager.getStatistics(action.url, action.token, temp); + + } return super.reduce(state, action); - case 'ics/nodestats-received': + case 'ics/statistics-error': + if (action.error.status === 400){ + // in case of bad request add the error message to the raw status + // most likely the statistics collection is disabled for this node + AppDispatcher.dispatch({ + type: 'ics/statistics-received', + data: action.error.response.text, + token: action.token, + ic: action.ic + }); + } else { + console.log("statistics error:", action.error); + } + return super.reduce(state, action); + + case 'ics/statistics-received': let tempIC2 = action.ic; if (!tempIC2.managedexternally) { if (tempIC2.statusupdateraw === null || tempIC2.statusupdateraw === undefined) { @@ -162,10 +183,6 @@ class InfrastructureComponentStore extends ArrayStore { } return super.reduce(state, action); - case 'ics/nodestats-error': - console.log("nodestats error:", action.error); - return super.reduce(state, action); - case 'ics/restart': ICsDataManager.restart(action.url, action.token); return super.reduce(state, action); diff --git a/src/ic/ics-data-manager.js b/src/ic/ics-data-manager.js index 43dc045..44c85c3 100644 --- a/src/ic/ics-data-manager.js +++ b/src/ic/ics-data-manager.js @@ -107,7 +107,8 @@ class IcsDataManager extends RestDataManager { type: 'ics/status-received', data: response, token: token, - ic: ic + ic: ic, + url: url }); }).catch(error => { AppDispatcher.dispatch({ @@ -116,34 +117,21 @@ class IcsDataManager extends RestDataManager { }) }) - // get name of websocket - /* - let ws_api = ic.websocketurl.split("/") - let ws_name = ws_api[ws_api.length-1] // websocket name is the last element in the websocket url - - RestAPI.get(url + "/node/" + ws_name + "/stats", null).then(response => { - AppDispatcher.dispatch({ - type: 'ics/nodestats-received', - data: response, - token: token, - ic: ic - }); - }).catch(error => { - AppDispatcher.dispatch({ - type: 'ics/nodestats-error', - error: error - }) - })*/ - } getConfig(url,token,ic){ - RestAPI.get(url + "node/" + ic.uuid, null).then(response => { + + // get the name of the node + let ws_api = ic.websocketurl.split("/") + let ws_name = ws_api[ws_api.length-1] // name is the last element in the websocket url + + RestAPI.get(url + "/node/" + ws_name, null).then(response => { AppDispatcher.dispatch({ type: 'ics/config-received', data: response, token: token, - ic: ic + ic: ic, + url: url }); }).catch(error => { AppDispatcher.dispatch({ @@ -154,7 +142,12 @@ class IcsDataManager extends RestDataManager { } getStatistics(url,token,ic){ - RestAPI.get(url + "/node/" +ic.uuid + "/stats", null).then(response => { + + // get the name of the node + let ws_api = ic.websocketurl.split("/") + let ws_name = ws_api[ws_api.length-1] // name is the last element in the websocket url + + RestAPI.get(url + "/node/" +ws_name + "/stats", null).then(response => { AppDispatcher.dispatch({ type: 'ics/statistics-received', data: response, @@ -164,7 +157,9 @@ class IcsDataManager extends RestDataManager { }).catch(error => { AppDispatcher.dispatch({ type: 'ics/statistics-error', - error: error + error: error, + token: token, + ic: ic }) }) } From 7935e8ff6a4b43f6923e4265c67690ab6570d24e Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 28 Apr 2021 11:58:51 +0200 Subject: [PATCH 04/25] add refresh of IC and status query to IC page; improve error handling for start parameter schema JSON view --- src/ic/ic.js | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index 9bb730f..b9f9575 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -61,6 +61,31 @@ class InfrastructureComponent extends React.Component { data: icID, token: this.state.sessionToken, }); + + // Start timer for periodic refresh + this.timer = window.setInterval(() => this.refresh(), 10000); + } + + refresh() { + + let icID = parseInt(this.props.match.params.ic, 10); + AppDispatcher.dispatch({ + type: 'ics/start-load', + token: this.state.sessionToken, + data: icID + }); + + // get status of VILLASnode and VILLASrelay ICs + if ((this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay") + && this.state.ic.apiurl !== '' && this.state.ic.apiurl !== undefined && this.state.ic.apiurl !== null && !this.state.ic.managedexternally) { + AppDispatcher.dispatch({ + type: 'ics/get-status', + url: this.state.ic.apiurl, + token: this.state.sessionToken, + ic: this.state.ic + }); + } + } isJSON(data) { @@ -102,12 +127,12 @@ class InfrastructureComponent extends React.Component { if(!canceled){ this.sendControlCommand(); } - + this.setState({confirmCommand: false, command: ''}); } - + async downloadGraph(url) { - + let blob = await fetch(url).then(r => r.blob()) FileSaver.saveAs(blob, this.props.ic.name + ".svg"); } @@ -172,14 +197,15 @@ class InfrastructureComponent extends React.Component { Start parameter schema - + /> :
No Start parameter schema JSON available.
} @@ -237,4 +263,4 @@ class InfrastructureComponent extends React.Component { } let fluxContainerConverter = require('../common/FluxContainerConverter'); -export default FluxContainer.create(fluxContainerConverter.convert(InfrastructureComponent), { withProps: true }); \ No newline at end of file +export default FluxContainer.create(fluxContainerConverter.convert(InfrastructureComponent), { withProps: true }); From ea0ec52902d94b1ec85448b295258ddac275397c Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Wed, 28 Apr 2021 14:04:49 +0200 Subject: [PATCH 05/25] WIP: IC page customization for VILLASnode #303 --- src/ic/ic.js | 21 +++++++++++++++++++++ src/ic/ics-data-manager.js | 8 ++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index b9f9575..f61bd3d 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -222,6 +222,27 @@ class InfrastructureComponent extends React.Component { collapsed={0} /> :
No valid JSON raw data available.
} + Raw Config + {this.isJSON(this.state.ic.statusupdateraw["config"]) ? + :
No valid config JSON raw data available.
} + Raw Statistics + {this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? + :
No valid statistics JSON raw data available.
} + {this.state.ic.type === "villas-node" ? <>
diff --git a/src/ic/ics-data-manager.js b/src/ic/ics-data-manager.js index 44c85c3..fcfd5db 100644 --- a/src/ic/ics-data-manager.js +++ b/src/ic/ics-data-manager.js @@ -102,7 +102,11 @@ class IcsDataManager extends RestDataManager { } getStatus(url,token,ic){ - RestAPI.get(url + "/status", null).then(response => { + let requestURL = url; + if(ic.type === "villas-node"){ + requestURL += "/status"; + } + RestAPI.get(requestURL, null).then(response => { AppDispatcher.dispatch({ type: 'ics/status-received', data: response, @@ -147,7 +151,7 @@ class IcsDataManager extends RestDataManager { let ws_api = ic.websocketurl.split("/") let ws_name = ws_api[ws_api.length-1] // name is the last element in the websocket url - RestAPI.get(url + "/node/" +ws_name + "/stats", null).then(response => { + RestAPI.get(url + "/node/" + ws_name + "/stats", null).then(response => { AppDispatcher.dispatch({ type: 'ics/statistics-received', data: response, From 81209d4ef0bee67f1eb0c85d1c5e06bdf46833f1 Mon Sep 17 00:00:00 2001 From: irismarie Date: Fri, 30 Apr 2021 16:53:35 +0200 Subject: [PATCH 06/25] small fixes --- src/ic/ic.js | 4 ++-- src/ic/ics.js | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index f61bd3d..0d2abfe 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -223,7 +223,7 @@ class InfrastructureComponent extends React.Component { /> :
No valid JSON raw data available.
} Raw Config - {this.isJSON(this.state.ic.statusupdateraw["config"]) ? + {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["config"]) ? :
No valid config JSON raw data available.
} Raw Statistics - {this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? + {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? Date: Mon, 3 May 2021 16:53:13 +0200 Subject: [PATCH 07/25] Major reworking of color picker and edit widget components that use it #312 --- src/signal/edit-signal-mapping.js | 2 - src/signal/signals-data-manager.js | 3 +- src/widget/edit-widget/color-picker.js | 110 +++++-------- .../edit-widget/edit-widget-color-control.js | 64 ++++---- .../edit-widget-color-zones-control.js | 154 +++++++++--------- .../edit-widget-control-creator.js | 2 +- .../edit-widget-plot-colors-control.js | 107 +++++++----- src/widget/widget-plot/plot-legend.js | 10 +- src/widget/widget-plot/plot.js | 7 +- 9 files changed, 225 insertions(+), 234 deletions(-) diff --git a/src/signal/edit-signal-mapping.js b/src/signal/edit-signal-mapping.js index e5bba88..cc235d2 100644 --- a/src/signal/edit-signal-mapping.js +++ b/src/signal/edit-signal-mapping.js @@ -95,7 +95,6 @@ class EditSignalMappingDialog extends React.Component { let signals = this.state.signals; let modifiedSignals = this.state.modifiedSignalIDs; - console.log("HandleMappingChange", row, column) if (column === 2) { // Name change signals[row].name = event.target.value; if (modifiedSignals.find(id => id === signals[row].id) === undefined) { @@ -112,7 +111,6 @@ class EditSignalMappingDialog extends React.Component { modifiedSignals.push(signals[row].id); } } else if (column === 1) { //index change - console.log("Index change") signals[row].index =parseInt(event.target.value, 10); if (modifiedSignals.find(id => id === signals[row].id) === undefined) { modifiedSignals.push(signals[row].id); diff --git a/src/signal/signals-data-manager.js b/src/signal/signals-data-manager.js index 1a5ee0c..b833534 100644 --- a/src/signal/signals-data-manager.js +++ b/src/signal/signals-data-manager.js @@ -71,7 +71,7 @@ class SignalsDataManager extends RestDataManager{ let configured = false; let error = false; for(let nodeConfig of nodes){ - console.log("parsing node config: ", nodeConfig) + //console.log("parsing node config: ", nodeConfig) if(!nodeConfig.hasOwnProperty("name")){ console.warn("Could not parse the following node config because it lacks a name parameter:", nodeConfig); } else if(nodeConfig.name === socketname){ @@ -128,7 +128,6 @@ class SignalsDataManager extends RestDataManager{ for (let outSig of nodeConfig.out.signals) { if (outSig.enabled) { - console.log("adding output signal:", outSig); let newSignal = { configID: configID, direction: 'out', diff --git a/src/widget/edit-widget/color-picker.js b/src/widget/edit-widget/color-picker.js index 8c148c0..4af998f 100644 --- a/src/widget/edit-widget/color-picker.js +++ b/src/widget/edit-widget/color-picker.js @@ -19,27 +19,29 @@ import React from 'react'; import { Form } from 'react-bootstrap'; import { SketchPicker } from 'react-color'; import Dialog from '../../common/dialogs/dialog'; +import {schemeCategory10} from "d3-scale-chromatic"; class ColorPicker extends React.Component { - valid = true; constructor(props) { super(props); this.state = { - widget: {} + rgbColor: {}, }; } - static getDerivedStateFromProps(props, state) { - return { - widget: props.widget - }; + componentDidUpdate(prevProps: Readonly

, prevState: Readonly, snapshot: SS) { + + if(this.props.show !== prevProps.show){ + // update color if show status of color picker has changed + this.setState({rgbColor: ColorPicker.hexToRgb(this.props.hexcolor,this.props.opacity)}) + } } - hexToRgb = (hex,opacity) => { - var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + static hexToRgb(hex,opacity) { + let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), @@ -49,27 +51,7 @@ class ColorPicker extends React.Component { } handleChangeComplete = (color) => { - let temp = this.state.widget; - - if (this.props.controlId === 'strokeStyle'){ - temp.customProperties.zones[this.props.zoneIndex]['strokeStyle'] = color.hex; - } - else if (this.props.controlId === 'lineColor'){ - temp.customProperties.lineColors[this.props.lineIndex] = color.hex; - } - else { - let parts = this.props.controlId.split('.'); - let isCustomProperty = true; - - if (parts.length === 1){ - isCustomProperty = false; - } - - isCustomProperty ? temp[parts[0]][parts[1]] = color.hex : temp[this.props.controlId] = color.hex; - isCustomProperty ? temp[parts[0]][parts[1] + "_opacity"] = color.rgb.a : temp[this.props.controlId +"_opacity"] = color.rgb.a; - } - - this.setState({ widget: temp }); + this.setState({rgbColor: color.rgb}) }; onClose = canceled => { @@ -81,52 +63,40 @@ class ColorPicker extends React.Component { return; } - if (this.valid && this.props.onClose != null) { - this.props.onClose(this.state.widget); + if (this.props.onClose != null) { + + const rgbToHex = (r, g, b) => '#' + [r, g, b].map(x => { + const hex = x.toString(16) + return hex.length === 1 ? '0' + hex : hex + }).join('') + + let data = { + hexcolor: rgbToHex(this.state.rgbColor.r, this.state.rgbColor.g,this.state.rgbColor.b), + opacity: this.state.rgbColor.a, + } + + this.props.onClose(data); } }; render() { - let hexColor; - let opacity = 1; - let parts = this.props.controlId.split('.'); - let isCustomProperty = true; - if (parts.length === 1) { - isCustomProperty = false; - } - if (this.props.controlId === 'strokeStyle') { - if (typeof this.state.widget.customProperties.zones[this.props.zoneIndex] !== 'undefined') { - hexColor = this.state.widget.customProperties.zones[this.props.zoneIndex]['strokeStyle']; - } - } - else if (this.props.controlId === 'lineColor') { - if (typeof this.state.widget.customProperties.lineColors[this.props.lineIndex] !== 'undefined') { - hexColor = this.state.widget.customProperties.lineColors[this.props.lineIndex]; - } - } - else{ - hexColor = isCustomProperty ? this.state.widget[parts[0]][parts[1]]: this.state.widget[this.props.controlId]; - opacity = isCustomProperty ? this.state.widget[parts[0]][parts[1] + "_opacity"]: this.state.widget[this.props.controlId + "_opacity"]; - } - - let rgbColor = this.hexToRgb(hexColor, opacity); - return

this.onClose(c)} - valid={true} - > -
- - -
; + return this.onClose(c)} + valid={true} + > +
+ + +
; } } diff --git a/src/widget/edit-widget/edit-widget-color-control.js b/src/widget/edit-widget/edit-widget-color-control.js index 6fd82f7..13c33b1 100644 --- a/src/widget/edit-widget/edit-widget-color-control.js +++ b/src/widget/edit-widget/edit-widget-color-control.js @@ -28,55 +28,51 @@ class EditWidgetColorControl extends Component { super(props); this.state = { - widget: {}, + color: null, + opacity: null, showColorPicker: false, originalColor: null }; } static getDerivedStateFromProps(props, state){ + let parts = props.controlId.split('.'); + let isCustomProperty = true; + if (parts.length === 1){ + isCustomProperty = false; + } + + let color = (isCustomProperty ? props.widget[parts[0]][parts[1]] : props.widget[props.controlId]); + let opacity = (isCustomProperty ? props.widget[parts[0]][parts[1] + "_opacity"] : props.widget[props.controlId + "_opacity"]); + return { - widget: props.widget + color: color, + opacity: opacity, }; } openColorPicker = () =>{ - let parts = this.props.controlId.split('.'); - let isCustomProperty = true; - if (parts.length === 1){ - isCustomProperty = false; - } - let color = (isCustomProperty ? this.props.widget[parts[0]][parts[1]] : this.props.widget[this.props.controlId]); - - this.setState({showColorPicker: true, originalColor: color}); + this.setState({showColorPicker: true, originalColor: this.state.color}); } - closeEditModal = (data) => { + closeColorPickerEditModal = (data) => { this.setState({showColorPicker: false}) - if(typeof data === 'undefined'){ - let parts = this.props.controlId.split('.'); - let isCustomProperty = true; - if (parts.length === 1) { - isCustomProperty = false; - } - let temp = this.state.widget; - isCustomProperty ? temp[parts[0]][parts[1]] = this.state.originalColor : temp[this.props.controlId] = this.state.originalColor; - this.setState({ widget: temp }); + if(typeof data === 'undefined'){ + + this.setState({ color: this.state.originalColor }); + } else { + // color picker with result data {hexcolor, opacity} + this.setState({color: data.hexcolor, opacity: data.opacity}) + this.props.handleChange({target: { id: this.props.controlId, value: data.hexcolor} }) + this.props.handleChange({target: { id: this.props.controlId + "_opacity", value: data.opacity} }) } } render() { - let parts = this.props.controlId.split('.'); - let isCustomProperty = true; - if (parts.length === 1){ - isCustomProperty = false; - } - let color = (isCustomProperty ? this.props.widget[parts[0]][parts[1]] : this.props.widget[this.props.controlId]); - let opacity = (isCustomProperty ? this.props.widget[parts[0]][parts[1] + "_opacity"] : this.props.widget[this.props.controlId + "_opacity"]); let style = { - backgroundColor: color, - opacity: opacity, + backgroundColor: this.state.color, + opacity: this.state.opacity, width: '80px', height: '40px', } @@ -85,8 +81,6 @@ class EditWidgetColorControl extends Component { if(this.props.disableOpacity){ tooltipText = "Change border color"; } - - return ( {this.props.label} @@ -100,7 +94,13 @@ class EditWidgetColorControl extends Component {
- this.closeEditModal(data)} widget={this.state.widget} controlId={this.props.controlId} disableOpacity={this.props.disableOpacity}/> + this.closeColorPickerEditModal(data)} + hexcolor={this.state.color} + opacity={this.state.opacity} + disableOpacity={this.props.disableOpacity} + /> ); diff --git a/src/widget/edit-widget/edit-widget-color-zones-control.js b/src/widget/edit-widget/edit-widget-color-zones-control.js index dd990bb..337e1d2 100644 --- a/src/widget/edit-widget/edit-widget-color-zones-control.js +++ b/src/widget/edit-widget/edit-widget-color-zones-control.js @@ -18,7 +18,6 @@ import React from 'react'; import { Form, Table, Button, Tooltip, OverlayTrigger } from 'react-bootstrap'; import ColorPicker from './color-picker' - import Icon from '../../common/icon'; import { Collapse } from 'react-collapse'; @@ -27,12 +26,7 @@ class EditWidgetColorZonesControl extends React.Component { super(props); this.state = { - widget: { - customProperties:{ - zones: [] - } - }, - selectedZone: null, + colorZones: [], selectedIndex: null, showColorPicker: false, originalColor: null, @@ -43,89 +37,88 @@ class EditWidgetColorZonesControl extends React.Component { static getDerivedStateFromProps(props, state){ return { - widget: props.widget + colorZones: props.widget.customProperties.zones }; } addZone = () => { // add row - const widget = this.state.widget; - widget.customProperties.zones.push({ strokeStyle: '#d3cbcb', min: 0, max: 100 }); + const zones = JSON.parse(JSON.stringify(this.state.colorZones)); + zones.push({ strokeStyle: '#d3cbcb', min: 0, max: 100 }); - if(widget.customProperties.zones.length > 0){ - let length = widget.customProperties.zones.length + if(zones.length > 0){ + let length = zones.length - for(let i= 0 ; i < length; i++){ - widget.customProperties.zones[i].min = i* 100/length; - widget.customProperties.zones[i].max = (i+1)* 100/length; - } + for(let i= 0 ; i < length; i++){ + zones[i].min = i* 100/length; + zones[i].max = (i+1)* 100/length; + } } - this.setState({ widget, selectedZone: null, selectedIndex: null }); - - this.sendEvent(widget); + this.setState({ colorZones: zones, selectedIndex: null }); + this.props.handleChange({target: { id: this.props.controlId, value: zones}}) } removeZones = () => { - - let temp = this.state.widget; - - temp.customProperties.zones.splice(this.state.selectedIndex, 1); - - if(temp.customProperties.zones.length > 0){ - let length = temp.customProperties.zones.length - + let zones = JSON.parse(JSON.stringify(this.state.colorZones)); + zones.splice(this.state.selectedIndex, 1); + if(zones.length > 0){ + let length = zones.length for(let i= 0 ; i < length; i++){ - temp.customProperties.zones[i].min = i* 100/length; - temp.customProperties.zones[i].max = (i+1)* 100/length; + zones[i].min = i* 100/length; + zones[i].max = (i+1)* 100/length; } - } - - this.setState({widget: temp,selectedZone: null, selectedIndex: null}); - + } + this.setState({colorZones: zones, selectedIndex: null}); + this.props.handleChange({target: { id: this.props.controlId, value: zones}}) } changeCell = (event, row, column) => { // change row - const widget = this.state.widget; + const zones = JSON.parse(JSON.stringify(this.state.colorZones)) if (column === 1) { - widget.customProperties.zones[row].strokeStyle = event.target.value; + zones[row].strokeStyle = event.target.value; } else if (column === 2) { - widget.customProperties.zones[row].min = event.target.value; + zones[row].min = event.target.value; } else if (column === 3) { - widget.customProperties.zones[row].max = event.target.value; + zones[row].max = event.target.value; } - this.setState({ widget }); - - this.sendEvent(widget); + this.setState({ colorZones: zones }); + this.props.handleChange({target: { id: this.props.controlId, value: zones}}) } editColorZone = (index) => { if(this.state.selectedIndex !== index){ - this.setState({selectedZone: this.state.widget.customProperties.zones[index], selectedIndex: index , minValue: this.state.widget.customProperties.zones[index].min, maxValue: this.state.widget.customProperties.zones[index].max}); + this.setState({ + selectedIndex: index , + minValue: this.state.colorZones[index].min, + maxValue: this.state.colorZones[index].max} + ); } else{ - this.setState({selectedZone: null, selectedIndex: null}); + this.setState({selectedIndex: null}); } } openColorPicker = () => { - - let color = this.state.selectedZone.strokeStyle; - + let color = this.state.colorZones[this.state.selectedIndex].strokeStyle; this.setState({showColorPicker: true, originalColor: color}); } - closeEditModal = (data) => { + closeColorPickerEditModal = (data) => { this.setState({showColorPicker: false}) + let zones = JSON.parse(JSON.stringify(this.state.colorZones)) if(typeof data === 'undefined'){ - let temp = this.state.selectedZone; - temp.strokeStyle = this.state.originalColor; - - this.setState({ selectedZone : temp }); + zones[this.state.selectedIndex].strokeStyle = this.state.originalColor + this.setState({ colorZones : zones }); + } else { + // color picker with result data {hexcolor, opacity} + zones[this.state.selectedIndex].strokeStyle = data.hexcolor + this.setState({ colorZones : zones }); + this.props.handleChange({target: { id: this.props.controlId, value: zones}}) } } @@ -134,14 +127,15 @@ class EditWidgetColorZonesControl extends React.Component { if(e.target.value < 0) return; this.setState({minValue: e.target.value}); - let temp = this.state.widget; - temp.customProperties.zones[this.state.selectedIndex]['min'] = e.target.value; + let zones = JSON.parse(JSON.stringify(this.state.colorZones)); + zones[this.state.selectedIndex]['min'] = e.target.value; if(this.state.selectedIndex !== 0){ - temp.customProperties.zones[this.state.selectedIndex - 1]['max'] = e.target.value + zones[this.state.selectedIndex - 1]['max'] = e.target.value } - this.setState({ widget: temp }); + this.setState({ colorZones: zones }); + this.props.handleChange({target: { id: this.props.controlId, value: zones}}) } handleMaxChange = (e) => { @@ -149,32 +143,19 @@ class EditWidgetColorZonesControl extends React.Component { if(e.target.value > 100) return; this.setState({maxValue: e.target.value}); - let temp = this.state.widget; - temp.customProperties.zones[this.state.selectedIndex]['max'] = e.target.value; + let zones = JSON.parse(JSON.stringify(this.state.colorZones)); + zones[this.state.selectedIndex]['max'] = e.target.value; - if(this.state.selectedIndex !== this.state.widget.customProperties.zones.length -1){ - temp.customProperties.zones[this.state.selectedIndex + 1]['min'] = e.target.value + if(this.state.selectedIndex !== zones.length -1){ + zones[this.state.selectedIndex + 1]['min'] = e.target.value } - this.setState({ widget: temp }); - } - - sendEvent(widget) { - // create event - const event = { - target: { - id: 'zones', - value: widget.customProperties.zones - } - }; - - this.props.handleChange(event); + this.setState({ colorZones: zones }); + this.props.handleChange({target: { id: this.props.controlId, value: zones}}) } - render() { - const buttonStyle = { marginBottom: '10px', marginLeft: '120px', @@ -187,9 +168,9 @@ class EditWidgetColorZonesControl extends React.Component { let tempColor = 'FFFFFF'; let collapse = false; - if(this.state.selectedZone !== null){ + if(this.state.selectedIndex !== null){ collapse = true; - tempColor = this.state.selectedZone.strokeStyle; + tempColor = this.state.colorZones[this.state.selectedIndex].strokeStyle; } let pickerStyle = { @@ -213,7 +194,7 @@ class EditWidgetColorZonesControl extends React.Component {
{ - this.state.widget.customProperties.zones.map((zone, idx) => { + this.state.colorZones.map((zone, idx) => { let color = zone.strokeStyle; let width = (zone.max - zone.min)*(260/100); let style = { @@ -222,7 +203,12 @@ class EditWidgetColorZonesControl extends React.Component { height: '40px' } return ( + style={style} + key={idx} + onClick={i => this.editColorZone(idx)} + disabled={!this.props.widget.customProperties.colorZones}> + + ) }) } @@ -258,10 +244,20 @@ class EditWidgetColorZonesControl extends React.Component { - + - this.closeEditModal(data)} widget={this.state.widget} zoneIndex={this.state.selectedIndex} controlId={'strokeStyle'} /> + this.closeColorPickerEditModal(data)} + hexcolor={tempColor} + opacity={1} + disableOpacity={this.props.disableOpacity} + /> ; } } diff --git a/src/widget/edit-widget/edit-widget-control-creator.js b/src/widget/edit-widget/edit-widget-control-creator.js index d2ee3fc..a207762 100644 --- a/src/widget/edit-widget/edit-widget-control-creator.js +++ b/src/widget/edit-widget/edit-widget-control-creator.js @@ -96,7 +96,7 @@ export default function CreateControls(widgetType = null, widget = null, session handleChange(e)} />, handleChange(e)} direction={'out'}/>, handleChange(e)} />, - handleChange(e)} />, + handleChange(e)} disableOpacity={true}/>, handleChange(e)} /> ); break; diff --git a/src/widget/edit-widget/edit-widget-plot-colors-control.js b/src/widget/edit-widget/edit-widget-plot-colors-control.js index fbef75c..4b4fcfc 100644 --- a/src/widget/edit-widget/edit-widget-plot-colors-control.js +++ b/src/widget/edit-widget/edit-widget-plot-colors-control.js @@ -19,10 +19,7 @@ import React, { Component } from 'react'; import { OverlayTrigger, Tooltip , Button, Form } from 'react-bootstrap'; import ColorPicker from './color-picker' import Icon from "../../common/icon"; -import { scaleOrdinal } from "d3-scale"; -import { schemeCategory10 } from "d3-scale-chromatic"; - -// schemeCategory20 no longer available in d3 +import {schemeCategory10} from "d3-scale-chromatic"; class EditWidgetPlotColorsControl extends Component { @@ -30,51 +27,78 @@ class EditWidgetPlotColorsControl extends Component { super(props); this.state = { - widget: {}, showColorPicker: false, originalColor: null, - selectedIndex: null + selectedIndex: null, + lineColors: [], + signalIDs: [] }; } - static getDerivedStateFromProps(props, state){ - - let widget = props.widget; - if(widget.customProperties.lineColors === undefined || widget.customProperties.lineColors === null){ - // for backwards compatibility with old plots - widget.customProperties.lineColors = [] - - const newLineColor = scaleOrdinal(schemeCategory10); - for (let signalID of widget.signalIDs){ - widget.customProperties.lineColors.push(newLineColor(signalID)) - } - } - + static getDerivedStateFromProps(props, state) { return { - widget: widget + lineColors: props.widget.customProperties.lineColors, + signalIDs: props.widget.signalIDs, }; } -//same here + componentDidUpdate(prevProps: Readonly

, prevState: Readonly, snapshot: SS) { - closeEditModal = (data) => { + let lineColorsChanged = false; + + if (JSON.stringify(this.state.signalIDs) !== JSON.stringify(prevState.signalIDs)){ + // if there was a change to the signal IDs + let tempLineColors = JSON.parse(JSON.stringify(this.state.lineColors)); + let oldNoSignals = tempLineColors.length + + if (this.state.signalIDs.length > prevState.signalIDs.length){ + // more signals than before + let diff = this.state.signalIDs.length - prevState.signalIDs.length + for (let i = 0; i { this.setState({showColorPicker: false}) + let tempLineColors = JSON.parse(JSON.stringify(this.state.lineColors)); if(typeof data === 'undefined'){ - - let temp = this.state.widget; - temp.customProperties.lineColors[this.state.selectedIndex] = this.state.originalColor; - this.setState({ widget: temp }); + // Color picker canceled + tempLineColors[this.state.selectedIndex] = this.state.originalColor; + this.setState({lineColors: tempLineColors}) + } else { + // color picker with result data {hexcolor, opacity} + tempLineColors[this.state.selectedIndex] = data.hexcolor + this.setState({lineColors: tempLineColors}) + this.props.handleChange({target: { id: this.props.controlId, value: tempLineColors} }) } } editLineColor = (index) => { if(this.state.selectedIndex !== index){ - let color = this.state.widget.customProperties.lineColors[index]; - this.setState({selectedIndex: index, showColorPicker: true, originalColor: color}); - } - else{ - this.setState({selectedIndex: null}); - } + let color = typeof this.state.lineColors[index] === "undefined" ? schemeCategory10[index % 10] : this.state.lineColors[index]; + this.setState({selectedIndex: index, showColorPicker: true, originalColor: color}); + } + else{ + this.setState({selectedIndex: null}); + } } render() { @@ -84,15 +108,15 @@ class EditWidgetPlotColorsControl extends Component { Line Colors

{ - this.state.widget.signalIDs.map((signalID, idx) => { - let color = this.state.widget.customProperties.lineColors[signalID]; - let width = 260 / this.state.widget.signalIDs.length; + this.props.widget.signalIDs.map((signalID, idx) => { + + let color = typeof this.state.lineColors[idx] === "undefined" ? schemeCategory10[idx % 10] : this.state.lineColors[idx]; + let width = 260 / this.props.widget.signalIDs.length; let style = { backgroundColor: color, width: width, height: '40px' } - let signal = this.props.signals.find(signal => signal.id === signalID); return this.editLineColor(signalID)} + onClick={i => this.editLineColor(idx)} > + ; }) }
- this.closeEditModal(data)} widget={this.state.widget} lineIndex={this.state.selectedIndex} controlId={'lineColor'} disableOpacity={true}/> + this.closeColorPickerEditModal(data)} + hexcolor={this.state.lineColors[this.state.selectedIndex]} + opacity={1} + disableOpacity={true} + /> ) diff --git a/src/widget/widget-plot/plot-legend.js b/src/widget/widget-plot/plot-legend.js index 00d1b77..310bc49 100644 --- a/src/widget/widget-plot/plot-legend.js +++ b/src/widget/widget-plot/plot-legend.js @@ -24,9 +24,7 @@ function Legend(props){ const signal = props.sig; const hasScalingFactor = (signal.scalingFactor !== 1); - const newLineColor = scaleOrdinal(schemeCategory10); - - let color = typeof props.lineColor === "undefined" ? newLineColor(signal.id) : props.lineColor; + let color = typeof props.lineColor === "undefined" ? schemeCategory10[props.index % 10] : props.lineColor; if(hasScalingFactor){ return ( @@ -52,11 +50,11 @@ class PlotLegend extends React.Component { return
    { this.props.lineColors !== undefined && this.props.lineColors != null ? ( - this.props.signals.map( signal => - + this.props.signals.map( (signal, idx) => + )) : ( this.props.signals.map( signal => - + )) }
diff --git a/src/widget/widget-plot/plot.js b/src/widget/widget-plot/plot.js index 17e61fc..0c92bc1 100644 --- a/src/widget/widget-plot/plot.js +++ b/src/widget/widget-plot/plot.js @@ -199,7 +199,6 @@ class Plot extends React.Component { // generate paths from data const sparkLine = line().x(p => xScale(p.x)).y(p => yScale(p.y)); - const newLineColor = scaleOrdinal(schemeCategory10); const lines = this.state.data.map((values, index) => { let signalID = this.props.signalIDs[index]; @@ -208,10 +207,10 @@ class Plot extends React.Component { this.props.lineColors = [] // for backwards compatibility } - if (typeof this.props.lineColors[signalID] === "undefined") { - this.props.lineColors[signalID] = newLineColor(signalID); + if (typeof this.props.lineColors[index] === "undefined") { + this.props.lineColors[index] = schemeCategory10[index % 10]; } - return + return }); this.setState({ lines, xAxis, yAxis }); From 2f2e6da54e9c4a120796f1d3263b905688951505 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 4 May 2021 11:12:03 +0200 Subject: [PATCH 08/25] move color picker to common folder --- src/{widget/edit-widget => common}/color-picker.js | 4 +--- src/widget/edit-widget/edit-widget-color-control.js | 2 +- src/widget/edit-widget/edit-widget-color-zones-control.js | 2 +- src/widget/edit-widget/edit-widget-plot-colors-control.js | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) rename src/{widget/edit-widget => common}/color-picker.js (96%) diff --git a/src/widget/edit-widget/color-picker.js b/src/common/color-picker.js similarity index 96% rename from src/widget/edit-widget/color-picker.js rename to src/common/color-picker.js index 4af998f..2b23b77 100644 --- a/src/widget/edit-widget/color-picker.js +++ b/src/common/color-picker.js @@ -18,9 +18,7 @@ import React from 'react'; import { Form } from 'react-bootstrap'; import { SketchPicker } from 'react-color'; -import Dialog from '../../common/dialogs/dialog'; -import {schemeCategory10} from "d3-scale-chromatic"; - +import Dialog from './dialogs/dialog'; class ColorPicker extends React.Component { diff --git a/src/widget/edit-widget/edit-widget-color-control.js b/src/widget/edit-widget/edit-widget-color-control.js index 13c33b1..0995453 100644 --- a/src/widget/edit-widget/edit-widget-color-control.js +++ b/src/widget/edit-widget/edit-widget-color-control.js @@ -17,7 +17,7 @@ import React, { Component } from 'react'; import { Form, OverlayTrigger, Tooltip, Button, Col } from 'react-bootstrap'; -import ColorPicker from './color-picker' +import ColorPicker from '../../common/color-picker' import Icon from "../../common/icon"; // schemeCategory20 no longer available in d3 diff --git a/src/widget/edit-widget/edit-widget-color-zones-control.js b/src/widget/edit-widget/edit-widget-color-zones-control.js index 337e1d2..9f12610 100644 --- a/src/widget/edit-widget/edit-widget-color-zones-control.js +++ b/src/widget/edit-widget/edit-widget-color-zones-control.js @@ -17,7 +17,7 @@ import React from 'react'; import { Form, Table, Button, Tooltip, OverlayTrigger } from 'react-bootstrap'; -import ColorPicker from './color-picker' +import ColorPicker from '../../common/color-picker' import Icon from '../../common/icon'; import { Collapse } from 'react-collapse'; diff --git a/src/widget/edit-widget/edit-widget-plot-colors-control.js b/src/widget/edit-widget/edit-widget-plot-colors-control.js index 4b4fcfc..8dc6f9e 100644 --- a/src/widget/edit-widget/edit-widget-plot-colors-control.js +++ b/src/widget/edit-widget/edit-widget-plot-colors-control.js @@ -17,7 +17,7 @@ import React, { Component } from 'react'; import { OverlayTrigger, Tooltip , Button, Form } from 'react-bootstrap'; -import ColorPicker from './color-picker' +import ColorPicker from '../../common/color-picker' import Icon from "../../common/icon"; import {schemeCategory10} from "d3-scale-chromatic"; From 5089db48ba6aae34013206491fcf888b32b600e8 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 4 May 2021 11:45:30 +0200 Subject: [PATCH 09/25] add propTypes to ColorPicker component --- src/common/color-picker.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/common/color-picker.js b/src/common/color-picker.js index 2b23b77..775e9c7 100644 --- a/src/common/color-picker.js +++ b/src/common/color-picker.js @@ -19,6 +19,7 @@ import React from 'react'; import { Form } from 'react-bootstrap'; import { SketchPicker } from 'react-color'; import Dialog from './dialogs/dialog'; +import PropTypes from 'prop-types' class ColorPicker extends React.Component { @@ -98,4 +99,12 @@ class ColorPicker extends React.Component { } } +ColorPicker.propTypes = { + onClose: PropTypes.func, + disableOpacity: PropTypes.bool, + show: PropTypes.bool, + hexcolor: PropTypes.string, + opacity: PropTypes.number +} + export default ColorPicker; From f0c8ee90050e15f96f672eb5597716cb7de99e81 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 4 May 2021 12:03:00 +0200 Subject: [PATCH 10/25] improve edit dialog for color zones --- .../edit-widget-color-zones-control.js | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/widget/edit-widget/edit-widget-color-zones-control.js b/src/widget/edit-widget/edit-widget-color-zones-control.js index 9f12610..46b4ed7 100644 --- a/src/widget/edit-widget/edit-widget-color-zones-control.js +++ b/src/widget/edit-widget/edit-widget-color-zones-control.js @@ -202,18 +202,24 @@ class EditWidgetColorZonesControl extends React.Component { width: width, height: '40px' } - return ( + return ( + + Edit zone} > + + + ) }) }
+ Edit selected color zone: Change color} > + Remove zone} > + + Date: Tue, 4 May 2021 13:01:06 +0200 Subject: [PATCH 11/25] fix edit user dialog --- src/user/edit-user.js | 97 +++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 59 deletions(-) diff --git a/src/user/edit-user.js b/src/user/edit-user.js index 5d20bf4..4925d57 100644 --- a/src/user/edit-user.js +++ b/src/user/edit-user.js @@ -21,28 +21,48 @@ import { Form, Col } from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; class EditUserDialog extends React.Component { - valid: true; - constructor(props) { super(props); this.state = { - username: props.user.username, - mail: props.user.mail, - role: props.user.role, - id: props.user.id, - active: props.user.active, - password: '', - confirmPassword: '', - oldPassword: '' + username: '', + mail: '', + role: '', + active: '', + password: "", + confirmPassword: "", + oldPassword: "", } } onClose(canceled) { if (canceled === false) { - if (this.valid) { - this.props.onClose(this.state); + + let user = {} + user.id = this.props.user.id; + + user.password = this.state.password; + user.confirmPassword = this.state.confirmPassword + user.oldpassword = this.state.oldPassword + + if (this.state.username != null && this.state.username !== this.props.user.username){ + user.username = this.state.username } + + if (this.state.mail != null && this.state.mail !== this.props.user.mail){ + user.mail = this.state.mail + } + + if (this.state.role != null && this.state.role !== this.props.user.role){ + user.role = this.state.role + } + + if (this.state.active != null && this.state.active !== this.props.user.active){ + user.active = this.state.active + } + + this.props.onClose(user); + } else { this.props.onClose(); } @@ -50,46 +70,6 @@ class EditUserDialog extends React.Component { handleChange(e) { this.setState({ [e.target.id]: e.target.value }); - - // check all controls - var username = true; - var role = true; - var mail = true; - var pw = true; - var active = true; - var confirmPassword = true; - var oldPassword = true; - - if (this.state.username === '') { - username = false; - } - - if (this.state.role === '') { - role = false; - } - - if (this.state.mail === '') { - mail = false; - } - - if (this.state.password === '') { - pw = false; - } - - if (this.state.active === '') { - active = false; - } - - if (this.state.confirmPassword === '') { - confirmPassword = false; - } - - if (this.state.oldPassword === '') { - oldPassword = false; - } - - // form is valid if any of the fields contain somethig - this.valid = username || role || mail || pw || active || confirmPassword || oldPassword; } resetState() { @@ -97,38 +77,37 @@ class EditUserDialog extends React.Component { username: this.props.user.username, mail: this.props.user.mail, role: this.props.user.role, - id: this.props.user.id }); } render() { return ( - this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}> + this.onClose(c)} onReset={() => this.resetState()} valid={true}>
Username - this.handleChange(e)} /> + this.handleChange(e)} /> E-mail - this.handleChange(e)} /> + this.handleChange(e)} /> Admin Password this.handleChange(e)} /> - Password + New User Password this.handleChange(e)} /> - Confirm New Password + Confirm new Password this.handleChange(e)} /> Role - this.handleChange(e)}> + this.handleChange(e)}> From 433c0918f260058a64beb1879ebf37341bc9fcae Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 4 May 2021 15:13:40 +0200 Subject: [PATCH 12/25] Fixes for editing users - edit user dialogs behave as expected - editing own user triggers update of LoginStore and local storage with updated user data --- src/user/edit-own-user.js | 74 +++++++++------------- src/user/edit-user.js | 3 + src/user/login-store.js | 11 ++-- src/user/user.js | 128 +++++++++++++++----------------------- src/user/users-store.js | 30 +++++++++ src/user/users.js | 6 +- 6 files changed, 125 insertions(+), 127 deletions(-) diff --git a/src/user/edit-own-user.js b/src/user/edit-own-user.js index a5b7756..8b49221 100644 --- a/src/user/edit-own-user.js +++ b/src/user/edit-own-user.js @@ -19,17 +19,16 @@ import React from 'react'; import { Form, Col } from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; +import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; +import NotificationsFactory from "../common/data-managers/notifications-factory"; class EditOwnUserDialog extends React.Component { - valid: true; - constructor(props) { super(props); this.state = { - username: this.props.user.username, - id: this.props.user.id, + username: "", mail: this.props.user.mail, password: '', oldPassword: '', @@ -39,9 +38,29 @@ class EditOwnUserDialog extends React.Component { onClose(canceled) { if (canceled === false) { - if (this.valid) { - this.props.onClose(this.state); + + let user = {}; + user.id = this.props.user.id; + user.password = this.state.password; + user.oldPassword = this.state.oldPassword; + user.confirmPassword = this.state.confirmPassword + + if (this.state.username != null && this.state.username !== this.props.user.username){ + user.username = this.state.username; } + + if (this.state.mail != null && this.state.mail !== this.props.user.mail){ + user.mail = this.state.mail; + } + + if (this.state.password !== '' && this.state.oldPassword !== '' && this.state.password === this.state.confirmPassword ) { + user.password = this.state.password; + user.oldPassword = this.state.oldPassword; + } else if (this.state.password !== '' && this.state.password !== this.state.confirmPassword) { + NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR('New password not correctly confirmed')); + } + + this.props.onClose(user); } else { this.props.onClose(); } @@ -49,42 +68,11 @@ class EditOwnUserDialog extends React.Component { handleChange(e) { this.setState({ [e.target.id]: e.target.value }); - - // check all controls - let username = true; - let mail = true; - let pw = true; - let oldPassword = true; - let confirmPassword = true; - - if (this.state.username === '') { - username = false; - } - - if (this.state.mail === '') { - mail = false; - } - - if (this.state.password === '') { - pw = false; - } - - if (this.state.oldPassword === '') { - oldPassword = false; - } - - if (this.state.confirmPassword === '') { - confirmPassword = false; - } - - // form is valid if the following condition is met - this.valid = username || mail || (oldPassword && pw && confirmPassword); } resetState() { this.setState({ username: this.props.user.username, - id: this.props.user.id, mail: this.props.user.mail, oldPassword: '', confirmPassword: '', @@ -94,28 +82,28 @@ class EditOwnUserDialog extends React.Component { render() { return ( - this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}> + this.onClose(c)} onReset={() => this.resetState()} valid={true}> Username - this.handleChange(e)} autocomplete="username" /> + this.handleChange(e)} autoComplete="username" /> E-mail - this.handleChange(e)} autocomplete="email" /> + this.handleChange(e)} autoComplete="email" /> Old Password - this.handleChange(e)} autocomplete="current-password" /> + this.handleChange(e)} autoComplete="current-password" /> New Password - this.handleChange(e)} autocomplete="new-password" /> + this.handleChange(e)} autoComplete="new-password" /> Confirm New Password - this.handleChange(e)} autocomplete="new-password" /> + this.handleChange(e)} autoComplete="new-password" /> diff --git a/src/user/edit-user.js b/src/user/edit-user.js index 4925d57..e5cc143 100644 --- a/src/user/edit-user.js +++ b/src/user/edit-user.js @@ -77,6 +77,9 @@ class EditUserDialog extends React.Component { username: this.props.user.username, mail: this.props.user.mail, role: this.props.user.role, + password: "", + confirmPassword: "", + oldPassword: "", }); } diff --git a/src/user/login-store.js b/src/user/login-store.js index 3e0eba6..f5cea52 100644 --- a/src/user/login-store.js +++ b/src/user/login-store.js @@ -66,11 +66,14 @@ class LoginStore extends ReduceStore { return Object.assign({}, state, { token: null, currentUser: null, loginMessage: null}); case 'users/logged-in': - // save login in local storage - localStorage.setItem('token', action.token); + // save login data in local storage and loginStore + let newState = state + if (action.token != null){ + localStorage.setItem('token', action.token); + newState = Object.assign({}, state, {token: action.token}) + } localStorage.setItem('currentUser', JSON.stringify(action.currentUser)); - - return Object.assign({}, state, { token: action.token, currentUser: action.currentUser}); + return Object.assign({}, newState, { currentUser: action.currentUser}); case 'users/login-error': if (action.error && !action.error.handled) { diff --git a/src/user/user.js b/src/user/user.js index 26bd161..a4cdfd6 100644 --- a/src/user/user.js +++ b/src/user/user.js @@ -15,100 +15,74 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React, { Component } from 'react'; +import React from 'react'; import { Container } from 'flux/utils'; -import { Button, Form, Row, Col } from 'react-bootstrap'; - +import { Form, Row, Col } from 'react-bootstrap'; import AppDispatcher from '../common/app-dispatcher'; -import UsersStore from './users-store'; - -import Icon from '../common/icon'; import EditOwnUserDialog from './edit-own-user' -import NotificationsDataManager from "../common/data-managers/notifications-data-manager" -import NotificationsFactory from "../common/data-managers/notifications-factory"; +import IconButton from "../common/icon-button"; +import LoginStore from './login-store' + +class User extends React.Component { + constructor() { + super(); + + this.state = { + token: LoginStore.getState().token, + editModal: false, + } + } -class User extends Component { static getStores() { - return [ UsersStore ]; + return [ LoginStore ]; } static calculateState(prevState, props) { - prevState = prevState || {}; - - let currentUserID = JSON.parse(localStorage.getItem("currentUser")).id; - let currentUser = UsersStore.getState().find(user => user.id === parseInt(currentUserID, 10)); - return { - currentUser, - token: localStorage.getItem("token"), - editModal: false, - }; - } - - componentDidMount() { - let currentUserID = JSON.parse(localStorage.getItem("currentUser")).id; - - AppDispatcher.dispatch({ - type: 'users/start-load', - data: parseInt(currentUserID, 10), - token: this.state.token - }); + currentUser: LoginStore.getState().currentUser + } } closeEditModal(data) { this.setState({ editModal: false }); - let updatedData = {} - let updatedUser = this.state.currentUser; - let hasChanged = false; - let pwChanged = false; - - updatedData.id = this.state.currentUser.id; - if (data) { - if (data.username !== this.state.currentUser.username) { - hasChanged = true; - updatedData.username = data.username; - updatedUser.username = data.username - } - - if (data.mail !== this.state.currentUser.mail) { - hasChanged = true; - updatedData.mail = data.mail; - updatedUser.mail = data.mail; - } - - if (data.password !== '' && data.oldPassword !== '' && data.password === data.confirmPassword ) { - pwChanged = true; - updatedData.password = data.password; - updatedData.oldPassword = data.oldPassword; - } else if (data.password !== '' && data.password !== data.confirmPassword) { - NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR('New password not correctly confirmed')); - return - } - - if (hasChanged || pwChanged) { - if (hasChanged){ - this.setState({ currentUser: updatedUser }) - } - - AppDispatcher.dispatch({ - type: 'users/start-edit', - data: updatedData, - token: this.state.token - }); - } else { - NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_WARNING('No update requested, no input data')); - } + AppDispatcher.dispatch({ + type: 'users/start-edit', + data: data, + token: this.state.token, + currentUser: this.state.currentUser, + }); } } render() { let user = this.state.currentUser; + const buttonStyle = { + marginLeft: '10px', + } + + const iconStyle = { + height: '30px', + width: '30px' + } + return (
-

Account

+

Account + + + this.setState({ editModal: true })} + icon='edit' + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> + +

{user ? <> @@ -116,30 +90,28 @@ class User extends Component { Username - + E-mail - + Role - + Created at - + - + Date: Tue, 4 May 2021 15:21:29 +0200 Subject: [PATCH 13/25] Move password confirmation check to edit user dialog --- src/user/edit-user.js | 13 +++++++++---- src/user/users.js | 16 ++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/user/edit-user.js b/src/user/edit-user.js index e5cc143..26a9fcb 100644 --- a/src/user/edit-user.js +++ b/src/user/edit-user.js @@ -19,6 +19,8 @@ import React from 'react'; import { Form, Col } from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; +import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; +import NotificationsFactory from "../common/data-managers/notifications-factory"; class EditUserDialog extends React.Component { constructor(props) { @@ -41,10 +43,6 @@ class EditUserDialog extends React.Component { let user = {} user.id = this.props.user.id; - user.password = this.state.password; - user.confirmPassword = this.state.confirmPassword - user.oldpassword = this.state.oldPassword - if (this.state.username != null && this.state.username !== this.props.user.username){ user.username = this.state.username } @@ -61,6 +59,13 @@ class EditUserDialog extends React.Component { user.active = this.state.active } + if (this.state.password !== '' && this.state.oldPassword !== '' && this.state.password === this.state.confirmPassword) { + user.password = this.state.password; + user.oldpassword = this.state.oldPassword + } else if (this.state.password !== '' && this.state.password !== this.state.confirmPassword){ + NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR("New password not correctly confirmed")) + } + this.props.onClose(user); } else { diff --git a/src/user/users.js b/src/user/users.js index d814ef5..a935e44 100644 --- a/src/user/users.js +++ b/src/user/users.js @@ -107,16 +107,12 @@ class Users extends Component { this.setState({ editModal: false }); if (data) { - if (data.password === data.confirmPassword) { - AppDispatcher.dispatch({ - type: 'users/start-edit', - data: data, - token: this.state.token, - currentUser: this.state.currentUser, - }); - } else { - NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR("New password not correctly confirmed")) - } + AppDispatcher.dispatch({ + type: 'users/start-edit', + data: data, + token: this.state.token, + currentUser: this.state.currentUser, + }); } } From 1a688e6df93f5880a36acfbe23b003b24f785b4e Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 4 May 2021 17:13:50 +0200 Subject: [PATCH 14/25] Websocket input signals: set length of values field prior to sending to avoid errors --- src/ic/ic-data-store.js | 1 + src/user/users.js | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ic/ic-data-store.js b/src/ic/ic-data-store.js index 7a81698..a6c53e0 100644 --- a/src/ic/ic-data-store.js +++ b/src/ic/ic-data-store.js @@ -110,6 +110,7 @@ class ICDataStore extends ReduceStore { state[action.ic].input.timestamp = Date.now(); state[action.ic].input.sequence++; state[action.ic].input.values[action.signal-1] = action.data; + state[action.ic].input.length = state[action.ic].input.values.length // copy of state needed because changes are not yet propagated let input = JSON.parse(JSON.stringify(state[action.ic].input)); diff --git a/src/user/users.js b/src/user/users.js index a935e44..db3a7ad 100644 --- a/src/user/users.js +++ b/src/user/users.js @@ -17,12 +17,10 @@ import React, { Component } from 'react'; import { Container } from 'flux/utils'; - import AppDispatcher from '../common/app-dispatcher'; import UsersStore from './users-store'; import LoginStore from './login-store'; import ScenarioStore from '../scenario/scenario-store'; - import Icon from '../common/icon'; import IconButton from '../common/icon-button'; import { Dropdown, DropdownButton } from 'react-bootstrap'; @@ -31,10 +29,7 @@ import TableColumn from '../common/table-column'; import NewUserDialog from './new-user'; import EditUserDialog from './edit-user'; import UsersToScenarioDialog from './users-to-scenario'; - import DeleteDialog from '../common/dialogs/delete-dialog'; -import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; -import NotificationsFactory from "../common/data-managers/notifications-factory"; class Users extends Component { static getStores() { From fdd345e2ee0e022e2c8bf918d0cf0d9f7ef2caec Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 4 May 2021 17:22:36 +0200 Subject: [PATCH 15/25] Slider: do not send value update to DB during continuous update #311 --- src/widget/widget.js | 20 +++++++++++--------- src/widget/widgets/button.js | 4 ++-- src/widget/widgets/input.js | 2 +- src/widget/widgets/slider.js | 8 ++++---- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/widget/widget.js b/src/widget/widget.js index 1523545..8e093c9 100644 --- a/src/widget/widget.js +++ b/src/widget/widget.js @@ -94,18 +94,20 @@ class Widget extends React.Component { }; } - inputDataChanged(widget, data, controlID, controlValue) { + inputDataChanged(widget, data, controlID, controlValue, isFinalChange) { // controlID is the path to the widget customProperty that is changed (for example 'value') // modify the widget customProperty if (controlID !== '') { let updatedWidget = JSON.parse(JSON.stringify(widget)); updatedWidget.customProperties[controlID] = controlValue; - AppDispatcher.dispatch({ - type: 'widgets/start-edit', - token: this.state.sessionToken, - data: updatedWidget - }); + if(isFinalChange) { + AppDispatcher.dispatch({ + type: 'widgets/start-edit', + token: this.state.sessionToken, + data: updatedWidget + }); + } } // The following assumes that a widget modifies/ uses exactly one signal @@ -185,21 +187,21 @@ class Widget extends React.Component { return this.inputDataChanged(widget, value, controlID, controlValue)} + onInputChanged={(value, controlID, controlValue, isFinalChange) => this.inputDataChanged(widget, value, controlID, controlValue, isFinalChange)} signals={this.state.signals} /> } else if (widget.type === 'NumberInput') { return this.inputDataChanged(widget, value, controlID, controlValue)} + onInputChanged={(value, controlID, controlValue, isFinalChange) => this.inputDataChanged(widget, value, controlID, controlValue, isFinalChange)} signals={this.state.signals} /> } else if (widget.type === 'Slider') { return this.inputDataChanged(widget, value, controlID, controlValue)} + onInputChanged={(value, controlID, controlValue, isFinalChange) => this.inputDataChanged(widget, value, controlID, controlValue, isFinalChange)} signals={this.state.signals} /> } else if (widget.type === 'Gauge') { diff --git a/src/widget/widgets/button.js b/src/widget/widgets/button.js index 897e1d9..f68144f 100644 --- a/src/widget/widgets/button.js +++ b/src/widget/widgets/button.js @@ -54,14 +54,14 @@ class WidgetButton extends Component { valueChanged(newValue, pressed) { if (this.props.onInputChanged) { - this.props.onInputChanged(newValue, 'pressed', pressed); + this.props.onInputChanged(newValue, 'pressed', pressed, true); } } render() { const buttonStyle = { - backgroundColor: this.props.widget.customProperties.background_color, + backgroundColor: this.props.widget.customProperties.background_color, borderColor: this.props.widget.customProperties.border_color, color: this.props.widget.customProperties.font_color, opacity: this.props.widget.customProperties.background_color_opacity diff --git a/src/widget/widgets/input.js b/src/widget/widgets/input.js index 21c0421..8d99564 100644 --- a/src/widget/widgets/input.js +++ b/src/widget/widgets/input.js @@ -73,7 +73,7 @@ class WidgetInput extends Component { valueChanged(newValue) { if (this.props.onInputChanged) { - this.props.onInputChanged(Number(newValue), 'value', Number(newValue)); + this.props.onInputChanged(Number(newValue), 'value', Number(newValue), true); } } diff --git a/src/widget/widgets/slider.js b/src/widget/widgets/slider.js index 23360d4..82b6926 100644 --- a/src/widget/widgets/slider.js +++ b/src/widget/widgets/slider.js @@ -79,14 +79,14 @@ class WidgetSlider extends Component { valueIsChanging(newValue) { this.props.widget.customProperties.value = newValue; if (this.props.widget.customProperties.continous_update) - this.valueChanged(newValue); + this.valueChanged(newValue, false); this.setState({ value: newValue }); } - valueChanged(newValue) { + valueChanged(newValue, isFinalChange) { if (this.props.onInputChanged) { - this.props.onInputChanged(newValue, 'value', newValue); + this.props.onInputChanged(newValue, 'value', newValue, isFinalChange); } } @@ -95,7 +95,7 @@ class WidgetSlider extends Component { let isVertical = this.props.widget.customProperties.orientation === WidgetSlider.OrientationTypes.VERTICAL.value; let fields = { name: this.props.widget.name, - control: this.valueIsChanging(v) } onAfterChange={ (v) => this.valueChanged(v) }/>, + control: this.valueIsChanging(v) } onAfterChange={ (v) => this.valueChanged(v, true) }/>, value: { format('.2f')(Number.parseFloat(this.state.value)) }, unit: { this.state.unit } } From 0ec419e0bcf20d0c2a84a11a6cb43b4d417eca45 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 5 May 2021 14:07:43 +0200 Subject: [PATCH 16/25] add showUnit property to customProperties of plot widget #313 --- src/dashboard/dashboard.js | 20 ++++++------- .../edit-widget-control-creator.js | 3 +- src/widget/widget-factory.js | 3 +- src/widget/widget-plot/plot-legend.js | 29 +++++++------------ src/widget/widgets/plot.js | 5 +++- 5 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/dashboard/dashboard.js b/src/dashboard/dashboard.js index 077de3f..d15a671 100644 --- a/src/dashboard/dashboard.js +++ b/src/dashboard/dashboard.js @@ -186,17 +186,17 @@ class Dashboard extends Component { componentDidUpdate(prevProps: Readonly

, prevState: Readonly, snapshot: SS) { // open web sockets if ICs are already known and sockets are not opened yet if (this.state.ics !== undefined && !Dashboard.webSocketsOpened) { - // only open sockets of ICs with configured input or output signals - let relevantICs = this.state.ics.filter(ic => { - let result = false; - this.state.configs.forEach(config => { - if(ic.id === config.icID && (config.inputLength !== 0 || config.outputLength !== 0)){ - result = true; - } + // only open sockets of ICs with configured input or output signals + let relevantICs = this.state.ics.filter(ic => { + let result = false; + this.state.configs.forEach(config => { + if(ic.id === config.icID && (config.inputLength !== 0 || config.outputLength !== 0)){ + result = true; + } + }) + return result; }) - return result; - }) - + if (relevantICs.length > 0) { console.log("Starting to open IC websockets:", relevantICs); AppDispatcher.dispatch({ diff --git a/src/widget/edit-widget/edit-widget-control-creator.js b/src/widget/edit-widget/edit-widget-control-creator.js index a207762..8eb6583 100644 --- a/src/widget/edit-widget/edit-widget-control-creator.js +++ b/src/widget/edit-widget/edit-widget-control-creator.js @@ -74,7 +74,8 @@ export default function CreateControls(widgetType = null, widget = null, session handleChange(e)} direction={'out'}/>, handleChange(e)} />, handleChange(e)} />, - handleChange(e)} /> + handleChange(e)} />, + handleChange(e)} /> ); break; case 'Table': diff --git a/src/widget/widget-factory.js b/src/widget/widget-factory.js index e3f4c2c..8a9baa8 100644 --- a/src/widget/widget-factory.js +++ b/src/widget/widget-factory.js @@ -90,6 +90,7 @@ class WidgetFactory { widget.customProperties.yMax = 10; widget.customProperties.yUseMinMax = false; widget.customProperties.lineColors = []; + widget.customProperties.showUnit = false; break; case 'Table': widget.minWidth = 200; @@ -150,7 +151,7 @@ class WidgetFactory { widget.customProperties.rangeMin = 0; widget.customProperties.rangeMax = 200; widget.customProperties.rangeUseMinMax = true; - widget.customProperties.showUnit = true; + widget.customProperties.showUnit = false; widget.customProperties.continous_update = false; widget.customProperties.default_value = '0'; widget.customProperties.value = ''; diff --git a/src/widget/widget-plot/plot-legend.js b/src/widget/widget-plot/plot-legend.js index 310bc49..096c67b 100644 --- a/src/widget/widget-plot/plot-legend.js +++ b/src/widget/widget-plot/plot-legend.js @@ -26,22 +26,13 @@ function Legend(props){ let color = typeof props.lineColor === "undefined" ? schemeCategory10[props.index % 10] : props.lineColor; - if(hasScalingFactor){ - return ( -

  • - {signal.name} - {signal.unit} - {signal.scalingFactor} -
  • - ) - } else { - return ( -
  • - {signal.name} - {signal.unit} -
  • - ) - } + return ( +
  • + {signal.name} + {props.showUnit ? {signal.unit} : <> } + {hasScalingFactor ? {signal.scalingFactor} : <>} +
  • + ) } class PlotLegend extends React.Component { @@ -51,10 +42,10 @@ class PlotLegend extends React.Component {
      { this.props.lineColors !== undefined && this.props.lineColors != null ? ( this.props.signals.map( (signal, idx) => - + )) : ( - this.props.signals.map( signal => - + this.props.signals.map( (signal, idx) => + )) }
    diff --git a/src/widget/widgets/plot.js b/src/widget/widgets/plot.js index 1479081..a9303ab 100644 --- a/src/widget/widgets/plot.js +++ b/src/widget/widgets/plot.js @@ -107,7 +107,10 @@ class WidgetPlot extends React.Component { signalIDs={this.props.widget.signalIDs} />
    - +
    ; } } From ac2883969bdcf73ddcebb494292cd36ccec08a3a Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 5 May 2021 14:14:12 +0200 Subject: [PATCH 17/25] fix a bug with the checkbox control in widget edit menus --- .../edit-widget-checkbox-control.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/widget/edit-widget/edit-widget-checkbox-control.js b/src/widget/edit-widget/edit-widget-checkbox-control.js index 6dd8ce0..9ea51c4 100644 --- a/src/widget/edit-widget/edit-widget-checkbox-control.js +++ b/src/widget/edit-widget/edit-widget-checkbox-control.js @@ -21,21 +21,19 @@ import { Form } from 'react-bootstrap'; class EditWidgetCheckboxControl extends React.Component { constructor(props) { super(props); + } - let parts = this.props.controlId.split('.'); - let isCustomProperty = true; - if (parts.length ===1){ - isCustomProperty = false; - } - + static getDerivedStateFromProps(props, state) { + let parts = props.controlId.split('.'); let isChecked; - if (isCustomProperty){ - isChecked = this.props.widget[parts[0]][parts[1]] - } else{ - isChecked = this.props.widget[this.props.controlId] + + if (parts.length ===1){ + isChecked = props.widget[props.controlId] + } else { + isChecked = props.widget[parts[0]][parts[1]] } - this.state = { + return { isChecked }; } From 92a4f5ec4d563d201a36394716b91b00a70c9330 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Wed, 5 May 2021 16:03:27 +0200 Subject: [PATCH 18/25] IC page: show only villas-relay status --- src/ic/ic.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index 0d2abfe..a62eaa2 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -211,8 +211,11 @@ class InfrastructureComponent extends React.Component { - Raw Status - {this.isJSON(this.state.ic.statusupdateraw) ? + + {this.state.ic.type === "villas-node" ? + <> + Raw Status + {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? :
    No valid statistics JSON raw data available.
    } - {this.state.ic.type === "villas-node" ? - <>
    @@ -275,6 +276,22 @@ class InfrastructureComponent extends React.Component { :
    } + {this.state.ic.type === "villas-relay" ? + <> + Raw Status + {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? + :
    No valid JSON raw data available.
    } + + : +
    } + From dd453f668e369386db44fe7db35e457680074e50 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Thu, 6 May 2021 01:01:15 +0200 Subject: [PATCH 19/25] IC page customization for VILLASnode and VILLASrelay #303 #304 #305 --- src/ic/ic.js | 109 +++++++++++++++++++++++++++++++++----------------- src/ic/ics.js | 13 ------ 2 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index a62eaa2..1d9a38c 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -62,9 +62,23 @@ class InfrastructureComponent extends React.Component { token: this.state.sessionToken, }); - // Start timer for periodic refresh - this.timer = window.setInterval(() => this.refresh(), 10000); + // get status of VILLASnode and VILLASrelay ICs + if(this.state.ic != undefined){ + if ((this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay") + && this.state.ic.apiurl !== '' && this.state.ic.apiurl !== undefined && this.state.ic.apiurl !== null && !this.state.ic.managedexternally) { + AppDispatcher.dispatch({ + type: 'ics/get-status', + url: this.state.ic.apiurl, + token: this.state.sessionToken, + ic: this.state.ic + }); + } } + else{ + this.timer = window.setInterval(() => this.refresh(), 10000); + } + } + refresh() { @@ -86,6 +100,10 @@ class InfrastructureComponent extends React.Component { }); } + if(this.timer){ + window.clearInterval(this.timer); + } + } isJSON(data) { @@ -212,40 +230,8 @@ class InfrastructureComponent extends React.Component { - {this.state.ic.type === "villas-node" ? + {this.state.ic.type === "villas-node" ? <> - Raw Status - {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? - :
    No valid JSON raw data available.
    } - - Raw Config - {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["config"]) ? - :
    No valid config JSON raw data available.
    } - Raw Statistics - {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? - :
    No valid statistics JSON raw data available.
    } -
    @@ -278,6 +264,10 @@ class InfrastructureComponent extends React.Component { {this.state.ic.type === "villas-relay" ? <> +
    + +
    Raw Status {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? :
    No valid JSON raw data available.
    } :
    } - + + {this.state.ic.type === "villas-node" ? + <> + + Raw Status + {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? + :
    No valid JSON raw data available.
    } + + + Raw Config + {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["config"]) ? + :
    No valid config JSON raw data available.
    } + + +
    + +
    + Raw Statistics + {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? + :
    No valid statistics JSON raw data available.
    } + + + :
    } +
    ; } diff --git a/src/ic/ics.js b/src/ic/ics.js index 01e9c0b..f64c47e 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -133,19 +133,6 @@ class InfrastructureComponents extends Component { token: this.state.sessionToken, }); - // get status of VILLASnode and VILLASrelay ICs - this.state.ics.forEach(ic => { - if ((ic.type === "villas-node" || ic.type === "villas-relay") - && ic.apiurl !== '' && ic.apiurl !== undefined && ic.apiurl !== null && !ic.managedexternally) { - AppDispatcher.dispatch({ - type: 'ics/get-status', - url: ic.apiurl, - token: this.state.sessionToken, - ic: ic - }); - } - }) - } } From 1c14087822243c22e66bd7f9824eefe2bea43d9b Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Thu, 6 May 2021 01:34:51 +0200 Subject: [PATCH 20/25] Replace IC page buttons with IconButtons --- src/ic/ic.js | 49 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index 1d9a38c..5752f3e 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -23,7 +23,7 @@ import { Container, Col, Row, Table, Button } from 'react-bootstrap'; import moment from 'moment'; import ReactJson from 'react-json-view'; import ConfirmCommand from './confirm-command'; -import Icon from "../common/icon"; +import IconButton from '../common/icon-button'; @@ -165,6 +165,15 @@ class InfrastructureComponent extends React.Component { graphURL = this.state.ic.apiurl + "/graph.svg" } + const buttonStyle = { + marginLeft: '5px', + } + + const iconStyle = { + height: '25px', + width: '25px' + } + return

    {this.state.ic.name}

    @@ -233,8 +242,14 @@ class InfrastructureComponent extends React.Component { {this.state.ic.type === "villas-node" ? <>
    - + this.downloadGraph(graphURL)} + icon='download' + buttonStyle={buttonStyle} + iconStyle={iconStyle} + />

    Graph: @@ -265,9 +280,15 @@ class InfrastructureComponent extends React.Component { {this.state.ic.type === "villas-relay" ? <>
    - -
    + this.refresh()} + icon='sync-alt' + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> +
    Raw Status {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? }
    +
    + this.refresh()} + icon='sync-alt' + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> +
    {this.state.ic.type === "villas-node" ? <> @@ -310,11 +341,7 @@ class InfrastructureComponent extends React.Component { collapsed={1} /> :
    No valid config JSON raw data available.
    } - -
    - -
    + Raw Statistics {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? Date: Thu, 6 May 2021 16:09:20 +0200 Subject: [PATCH 21/25] reinsert IC status refresh on ICs page --- src/ic/ics.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ic/ics.js b/src/ic/ics.js index f64c47e..f0d7a8d 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -134,6 +134,20 @@ class InfrastructureComponents extends Component { }); } + + // get status of VILLASnode and VILLASrelay ICs + this.state.ics.forEach(ic => { + if ((ic.type === "villas-node" || ic.type === "villas-relay") + && ic.apiurl !== '' && ic.apiurl !== undefined && ic.apiurl !== null && !ic.managedexternally) { + AppDispatcher.dispatch({ + type: 'ics/get-status', + url: ic.apiurl, + token: this.state.sessionToken, + ic: ic + }); + } + }) + } closeNewModal(data) { From 57e6a6c3d064e8ebb4202c5afbeb61e4b0855bce Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Thu, 6 May 2021 16:35:10 +0200 Subject: [PATCH 22/25] minor fixes in IC pages for VILLASnode and VILLASrelay #304 #303 - fix indentation - fix loading of IC and refresh of status - add missing IC data store - show refresh button only for villas-node and villas-relay - remove duplicated function --- src/ic/ic.js | 607 ++++++++++++++++++++++++--------------------------- 1 file changed, 287 insertions(+), 320 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index 5752f3e..ed5c8ef 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -16,7 +16,8 @@ ******************************************************************************/ import React from 'react'; -import InfrastructureComponentStore from './ic-store'; +import ICstore from './ic-store'; +import ICdataStore from './ic-data-store' import { Container as FluxContainer } from 'flux/utils'; import AppDispatcher from '../common/app-dispatcher'; import { Container, Col, Row, Table, Button } from 'react-bootstrap'; @@ -28,338 +29,304 @@ import IconButton from '../common/icon-button'; class InfrastructureComponent extends React.Component { - constructor(props) { - super(props); + constructor(props) { + super(props); - this.state = { - confirmCommand: false, - command: '', - }; + this.state = { + confirmCommand: false, + command: '', + sessionToken: localStorage.getItem("token"), + currentUser: JSON.parse(localStorage.getItem("currentUser")), + }; + } + + static getStores() { + return [ICstore, ICdataStore]; + } + + static calculateState(prevState, props) { + return { + ic: ICstore.getState().find(ic => ic.id === parseInt(props.match.params.ic, 10)) + } + } + + componentDidMount() { + let icID = parseInt(this.props.match.params.ic, 10); + + AppDispatcher.dispatch({ + type: 'ics/start-load', + data: icID, + token: this.state.sessionToken, + }); + } + + + refresh() { + // get status of VILLASnode and VILLASrelay ICs + if ((this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay") + && this.state.ic.apiurl !== '' && this.state.ic.apiurl !== undefined && this.state.ic.apiurl !== null && !this.state.ic.managedexternally) { + AppDispatcher.dispatch({ + type: 'ics/get-status', + url: this.state.ic.apiurl, + token: this.state.sessionToken, + ic: this.state.ic + }); + } + } + + isJSON(data) { + if (data === undefined || data === null) { + return false; + } + let str = JSON.stringify(data); + try { + JSON.parse(str) + } + catch (ex) { + return false + } + return true + } + + async downloadGraph(url) { + let blob = await fetch(url).then(r => r.blob()) + FileSaver.saveAs(blob, this.state.ic.name + ".svg"); + } + + sendControlCommand() { + if (this.state.command === "restart") { + AppDispatcher.dispatch({ + type: 'ics/restart', + url: this.state.ic.apiurl + "/restart", + token: this.state.sessionToken, + }); + } else if (this.state.command === "shutdown") { + AppDispatcher.dispatch({ + type: 'ics/shutdown', + url: this.state.ic.apiurl + "/shutdown", + token: this.state.sessionToken, + }); + } + } + + confirmCommand(canceled){ + if(!canceled){ + this.sendControlCommand(); } - static getStores() { - return [InfrastructureComponentStore]; + this.setState({confirmCommand: false, command: ''}); + } + + + render() { + if (this.state.ic === undefined) { + return

    Loading Infrastructure Component...

    ; } - static calculateState(prevState, props) { - if (prevState == null) { - prevState = {}; - } - - return { - sessionToken: localStorage.getItem("token"), - currentUser: JSON.parse(localStorage.getItem("currentUser")), - ic: InfrastructureComponentStore.getState().find(ic => ic.id === parseInt(props.match.params.ic, 10)) - } + let graphURL = "" + if (this.state.ic.apiurl !== "") { + graphURL = this.state.ic.apiurl + "/graph.svg" } - componentDidMount() { - let icID = parseInt(this.props.match.params.ic, 10); - - AppDispatcher.dispatch({ - type: 'ics/start-load', - data: icID, - token: this.state.sessionToken, - }); - - // get status of VILLASnode and VILLASrelay ICs - if(this.state.ic != undefined){ - if ((this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay") - && this.state.ic.apiurl !== '' && this.state.ic.apiurl !== undefined && this.state.ic.apiurl !== null && !this.state.ic.managedexternally) { - AppDispatcher.dispatch({ - type: 'ics/get-status', - url: this.state.ic.apiurl, - token: this.state.sessionToken, - ic: this.state.ic - }); - } - } - else{ - this.timer = window.setInterval(() => this.refresh(), 10000); - } + const buttonStyle = { + marginLeft: '5px', } - - refresh() { - - let icID = parseInt(this.props.match.params.ic, 10); - AppDispatcher.dispatch({ - type: 'ics/start-load', - token: this.state.sessionToken, - data: icID - }); - - // get status of VILLASnode and VILLASrelay ICs - if ((this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay") - && this.state.ic.apiurl !== '' && this.state.ic.apiurl !== undefined && this.state.ic.apiurl !== null && !this.state.ic.managedexternally) { - AppDispatcher.dispatch({ - type: 'ics/get-status', - url: this.state.ic.apiurl, - token: this.state.sessionToken, - ic: this.state.ic - }); - } - - if(this.timer){ - window.clearInterval(this.timer); - } - + const iconStyle = { + height: '25px', + width: '25px' } - isJSON(data) { - if (data === undefined || data === null) { - return false; - } - let str = JSON.stringify(data); - try { - JSON.parse(str) - } - catch (ex) { - return false - } - return true - } - - async downloadGraph(url) { - let blob = await fetch(url).then(r => r.blob()) - FileSaver.saveAs(blob, this.state.ic.name + ".svg"); - } - - sendControlCommand() { - if (this.state.command === "restart") { - AppDispatcher.dispatch({ - type: 'ics/restart', - url: this.state.ic.apiurl + "/restart", - token: this.state.sessionToken, - }); - } else if (this.state.command === "shutdown") { - AppDispatcher.dispatch({ - type: 'ics/shutdown', - url: this.state.ic.apiurl + "/shutdown", - token: this.state.sessionToken, - }); - } - } - - confirmCommand(canceled){ - if(!canceled){ - this.sendControlCommand(); - } - - this.setState({confirmCommand: false, command: ''}); - } - - async downloadGraph(url) { - - let blob = await fetch(url).then(r => r.blob()) - FileSaver.saveAs(blob, this.props.ic.name + ".svg"); - } - - render() { - if (this.state.ic === undefined) { - return

    Loading Infrastructure Component...

    ; - } - - let graphURL = "" - if (this.state.ic.apiurl !== "") { - graphURL = this.state.ic.apiurl + "/graph.svg" - } - - const buttonStyle = { - marginLeft: '5px', - } - - const iconStyle = { - height: '25px', - width: '25px' - } - - return
    -

    {this.state.ic.name}

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Name{this.state.ic.name}
    Description{this.state.ic.description}
    UUID{this.state.ic.uuid}
    State{this.state.ic.state}
    Category{this.state.ic.category}
    Type{this.state.ic.type}
    Uptime{moment.duration(this.state.ic.uptime, "seconds").humanize()}
    Location{this.state.ic.location}
    Websocket URL{this.state.ic.websocketurl}
    API URL{this.state.ic.apiurl}
    Start parameter schema - {this.isJSON(this.state.ic.startparameterschema) ? - :
    No Start parameter schema JSON available.
    } -
    - - - {this.state.ic.type === "villas-node" ? - <> -
    - this.downloadGraph(graphURL)} - icon='download' - buttonStyle={buttonStyle} - iconStyle={iconStyle} - /> -
    -
    - Graph: -
    - {"Graph -
    - - {this.state.currentUser.role === "Admin" ? -
    -
    - Controls: -
    - - -
    -
    - :
    - } - this.confirmCommand(c)} /> - - :
    } - - {this.state.ic.type === "villas-relay" ? - <> -
    - this.refresh()} - icon='sync-alt' - buttonStyle={buttonStyle} - iconStyle={iconStyle} - /> -
    - Raw Status - {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? - :
    No valid JSON raw data available.
    } - - : -
    } - - + return
    +

    {this.state.ic.name}

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name{this.state.ic.name}
    Description{this.state.ic.description}
    UUID{this.state.ic.uuid}
    State{this.state.ic.state}
    Category{this.state.ic.category}
    Type{this.state.ic.type}
    Uptime{moment.duration(this.state.ic.uptime, "seconds").humanize()}
    Location{this.state.ic.location}
    Websocket URL{this.state.ic.websocketurl}
    API URL{this.state.ic.apiurl}
    Start parameter schema + {this.isJSON(this.state.ic.startparameterschema) ? + :
    No Start parameter schema JSON available.
    } +
    + + + {this.state.ic.type === "villas-node" ? + <>
    - this.refresh()} - icon='sync-alt' - buttonStyle={buttonStyle} - iconStyle={iconStyle} - /> -
    - - {this.state.ic.type === "villas-node" ? - <> - - Raw Status - {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? - :
    No valid JSON raw data available.
    } - - - Raw Config - {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["config"]) ? - :
    No valid config JSON raw data available.
    } - - - Raw Statistics - {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? - :
    No valid statistics JSON raw data available.
    } - - - :
    } - - -
    ; - } + this.downloadGraph(graphURL)} + icon='download' + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> +
    +
    + Graph: +
    + {"Graph +
    + {this.state.currentUser.role === "Admin" ? +
    +
    + Controls: +
    + + +
    +
    + :
    + } + this.confirmCommand(c)} + /> + + :
    } + + {this.state.ic.type === "villas-relay" ? + <> +
    + this.refresh()} + icon='sync-alt' + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> +
    + Raw Status + {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? + :
    No valid JSON raw data available.
    } + + : +
    } + + + {this.state.ic.type === "villas-node" ? + <> +
    + this.refresh()} + icon='sync-alt' + buttonStyle={buttonStyle} + iconStyle={iconStyle} + /> +
    + + + + Raw Status + {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? + :
    No valid JSON raw data available.
    } + + + Raw Config + {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["config"]) ? + :
    No valid config JSON raw data available.
    } + + + Raw Statistics + {this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["statistics"]) ? + :
    No valid statistics JSON raw data available.
    } + + +
    + :
    } + +
    ; + } } let fluxContainerConverter = require('../common/FluxContainerConverter'); From 9a82072b36d8523e9052beae4deee0570757b6be Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Thu, 6 May 2021 16:35:49 +0200 Subject: [PATCH 23/25] add missing stores in scenario and scenarios component --- src/scenario/scenario.js | 3 ++- src/scenario/scenarios.js | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index d9e9d4c..57e7a15 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -30,6 +30,7 @@ import SignalStore from '../signal/signal-store' import FileStore from "../file/file-store" import WidgetStore from "../widget/widget-store"; import ResultStore from "../result/result-store" +import UsersStore from "../user/users-store" import DashboardTable from '../dashboard/dashboard-table' import ResultTable from "../result/result-table"; @@ -67,7 +68,7 @@ class Scenario extends React.Component { } static getStores() { - return [ScenarioStore, ConfigStore, DashboardStore, ICStore, SignalStore, FileStore, WidgetStore, ResultStore]; + return [ScenarioStore, ConfigStore, DashboardStore, ICStore, SignalStore, FileStore, WidgetStore, ResultStore, UsersStore]; } componentDidMount() { diff --git a/src/scenario/scenarios.js b/src/scenario/scenarios.js index 51f8d3e..4a3ecbb 100644 --- a/src/scenario/scenarios.js +++ b/src/scenario/scenarios.js @@ -18,21 +18,19 @@ import React, { Component } from 'react'; import { Container } from 'flux/utils'; import FileSaver from 'file-saver'; - import AppDispatcher from '../common/app-dispatcher'; import ScenarioStore from './scenario-store'; import DashboardStore from '../dashboard/dashboard-store'; import WidgetStore from "../widget/widget-store"; import ConfigStore from '../componentconfig/config-store'; import SignalStore from '../signal/signal-store' - -import Icon from '../common/icon'; +import ResultStore from '../result/result-store' +import FileStore from '../file/file-store' import Table from '../common/table'; import TableColumn from '../common/table-column'; import NewScenarioDialog from './new-scenario'; import EditScenarioDialog from './edit-scenario'; import ImportScenarioDialog from './import-scenario'; - import DeleteDialog from '../common/dialogs/delete-dialog'; import IconButton from '../common/icon-button'; @@ -40,7 +38,7 @@ import IconButton from '../common/icon-button'; class Scenarios extends Component { static getStores() { - return [ScenarioStore, DashboardStore, WidgetStore, ConfigStore, SignalStore]; + return [ScenarioStore, DashboardStore, WidgetStore, ConfigStore, SignalStore, ResultStore, FileStore]; } static calculateState(prevState, props) { From 16c0dd176040619ed1b05c7ca2f0ec3836da168e Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Fri, 7 May 2021 10:09:43 +0200 Subject: [PATCH 24/25] Fixes in IC data store for status queries of VILLASnode and VILLASrelay #303 #304 - query config and statistics only for type villas-node - query status only for category gateway - update UUID of IC based on raw status --- src/ic/ic-store.js | 11 +++++++++-- src/ic/ic.js | 2 +- src/ic/ics.js | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index 385af58..eb6acf9 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -118,13 +118,17 @@ class InfrastructureComponentStore extends ArrayStore { tempIC.state = action.data.state; tempIC.uptime = action.data.time_now - action.data.time_started; tempIC.statusupdateraw = action.data + tempIC.uuid = action.data.uuid AppDispatcher.dispatch({ type: 'ics/start-edit', data: tempIC, token: action.token, }); - ICsDataManager.getConfig(action.url, action.token, tempIC); + if(tempIC.type === "villas-node"){ + ICsDataManager.getConfig(action.url, action.token, tempIC); + } + } return super.reduce(state, action); @@ -148,7 +152,10 @@ class InfrastructureComponentStore extends ArrayStore { data: temp, token: action.token, }); - ICsDataManager.getStatistics(action.url, action.token, temp); + + if(temp.type === "villas-node") { + ICsDataManager.getStatistics(action.url, action.token, temp); + } } return super.reduce(state, action); diff --git a/src/ic/ic.js b/src/ic/ic.js index ed5c8ef..0bbd368 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -63,7 +63,7 @@ class InfrastructureComponent extends React.Component { refresh() { // get status of VILLASnode and VILLASrelay ICs - if ((this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay") + if (this.state.ic.category === "gateway" && (this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay") && this.state.ic.apiurl !== '' && this.state.ic.apiurl !== undefined && this.state.ic.apiurl !== null && !this.state.ic.managedexternally) { AppDispatcher.dispatch({ type: 'ics/get-status', diff --git a/src/ic/ics.js b/src/ic/ics.js index f0d7a8d..7452fa8 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -137,7 +137,7 @@ class InfrastructureComponents extends Component { // get status of VILLASnode and VILLASrelay ICs this.state.ics.forEach(ic => { - if ((ic.type === "villas-node" || ic.type === "villas-relay") + if (ic.category === "gateway" && (ic.type === "villas-node" || ic.type === "villas-relay") && ic.apiurl !== '' && ic.apiurl !== undefined && ic.apiurl !== null && !ic.managedexternally) { AppDispatcher.dispatch({ type: 'ics/get-status', From 9f1555ba730c170d39a1aa2f498fc56bd2b311d8 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Fri, 7 May 2021 10:20:22 +0200 Subject: [PATCH 25/25] add missing FileSaver import in IC page, add horizontal line in villas-relay (gateway) page --- src/ic/ic.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ic/ic.js b/src/ic/ic.js index 0bbd368..40e300b 100644 --- a/src/ic/ic.js +++ b/src/ic/ic.js @@ -25,6 +25,7 @@ import moment from 'moment'; import ReactJson from 'react-json-view'; import ConfirmCommand from './confirm-command'; import IconButton from '../common/icon-button'; +import FileSaver from 'file-saver'; @@ -202,7 +203,7 @@ class InfrastructureComponent extends React.Component { - {this.state.ic.type === "villas-node" ? + {this.state.category ==="gateway" && this.state.ic.type === "villas-node" ? <>
    :
    } - {this.state.ic.type === "villas-relay" ? + {this.state.category ==="gateway" && this.state.ic.type === "villas-relay" ? <>
    +
    Raw Status {this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ? } - {this.state.ic.type === "villas-node" ? + {this.state.category ==="gateway" && this.state.ic.type === "villas-node" ? <>