From 8d0b86e242ee21d6450bdd68e84063550dd79ece Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Mon, 6 Jul 2020 16:57:49 +0200 Subject: [PATCH 01/30] Show multiple selected files in component config table; add column for simulation model; allow for selection of multiple files per component config in edit dialog #234 --- package-lock.json | 9 +++++ package.json | 1 + src/componentconfig/edit-config.js | 56 ++++++++++++++++++++---------- src/scenario/scenario.js | 21 ++++++++--- 4 files changed, 64 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56c4421..5ad0112 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8902,6 +8902,15 @@ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, + "multiselect-react-dropdown": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/multiselect-react-dropdown/-/multiselect-react-dropdown-1.5.7.tgz", + "integrity": "sha512-bDlXYEzpV/5p5G5nIFRrZ/Ndf8CSYWliZ62n/5imfjLy0K2/dNx6sFmk4W/Phq83bzPUDK/RI4553yCk6YzZwg==", + "requires": { + "react": "^16.7.0", + "react-dom": "^16.7.0" + } + }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", diff --git a/package.json b/package.json index 0f50af1..11aceb7 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "jszip": "^3.5.0", "libcimsvg": "git+https://git.rwth-aachen.de/acs/public/cim/pintura-npm-package.git", "lodash": "^4.17.15", + "multiselect-react-dropdown": "^1.5.7", "node-sass": "^4.14.1", "popper.js": "^1.16.1", "prop-types": "^15.7.2", diff --git a/src/componentconfig/edit-config.js b/src/componentconfig/edit-config.js index a69159d..ba6e413 100644 --- a/src/componentconfig/edit-config.js +++ b/src/componentconfig/edit-config.js @@ -17,6 +17,7 @@ import React from 'react'; import {FormGroup, FormControl, FormLabel} from 'react-bootstrap'; +import { Multiselect } from 'multiselect-react-dropdown' import Dialog from '../common/dialogs/dialog'; import ParametersEditor from '../common/parameters-editor'; import SelectFile from "../file/select-file"; @@ -28,12 +29,11 @@ class EditConfigDialog extends React.Component { super(props); this.state = { - selectedFile: null, name: '', icID: '', configuration: null, startParameters: this.props.config.startParameters, - selectedFileID: this.props.config.selectedFileID + fileIDs: this.props.config.fileIDs }; } @@ -52,9 +52,13 @@ class EditConfigDialog extends React.Component { if(this.state.startParameters !== {} && JSON.stringify(this.props.config.startParameters) !== JSON.stringify(this.state.startParameters)){ data.startParameters = this.state.startParameters; } - if (parseInt(this.state.selectedFileID, 10) !== 0 && - this.props.config.selectedFileID !== parseInt(this.state.selectedFileID)) { - data.selectedFileID = parseInt(this.state.selectedFileID, 10); + + let IDs = [] + for(let e of this.state.fileIDs){ + IDs.push(e.id) + } + if (JSON.stringify(IDs) !== JSON.stringify(this.props.config.fileIDs)){ + data.fileIDs = IDs; } //forward modified config to callback function @@ -79,10 +83,19 @@ class EditConfigDialog extends React.Component { this.valid = this.isValid() } - handleSelectedFileChange(event){ - //console.log("Config file change to: ", event.target.value); - this.setState({selectedFileID: event.target.value}) + onFileSelect(selectedList, selectedItem) { + this.setState({ + fileIDs: selectedList + }) + this.valid = this.isValid() + } + + onFileRemove(selectedList, removedItem) { + + this.setState({ + fileIDs: selectedList + }) this.valid = this.isValid() } @@ -91,9 +104,7 @@ class EditConfigDialog extends React.Component { return this.state.name !== '' || this.state.icID !== '' || this.state.startParameters !== {} - || this.state.selectedFile != null || this.state.configuration != null - || this.state.selectedFileID !== 0; } resetState() { @@ -105,6 +116,15 @@ class EditConfigDialog extends React.Component { ); + let configFileOptions = []; + for(let file of this.props.files) { + configFileOptions.push( + {name: file.name, id: file.id} + ); + } + + + return ( this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
@@ -121,14 +141,14 @@ class EditConfigDialog extends React.Component { - this.handleSelectedFileChange(e)} - files={this.props.files} - value={this.state.selectedFileID} - scenarioID={this.props.config.scenarioID} - sessionToken={this.props.sessionToken} + this.onFileSelect(selectedList, selectedItem)} + onRemove={(selectedList, removedItem) => this.onFileRemove(selectedList, removedItem)} + displayValue={'name'} + placeholder={'Select file(s)...'} /> diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 8d3495e..8e2ceda 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -396,12 +396,22 @@ class Scenario extends React.Component { * File modification methods ############################################## */ - getFileName(id) { - for (let file of this.state.files) { - if (file.id === id) { - return file.name; + getListOfFiles(fileIDs, type) { + + let fileList = ''; + + for (let id of fileIDs){ + for (let file of this.state.files) { + if (file.id === id && (type === 'all' || file.type.includes(type))) { + fileList = fileList + '\n' + file.name; + } } } + + + + + return fileList; } /* ############################################## @@ -428,7 +438,8 @@ class Scenario extends React.Component { this.onConfigChecked(index, event)} width='30' /> - this.getFileName(selectedFileID)} /> + this.getListOfFiles(fileIDs, 'all')} /> + this.getListOfFiles(fileIDs, 'xml')} /> Date: Mon, 6 Jul 2020 16:58:25 +0200 Subject: [PATCH 02/30] remove unused import --- src/componentconfig/edit-config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/componentconfig/edit-config.js b/src/componentconfig/edit-config.js index ba6e413..2e277b1 100644 --- a/src/componentconfig/edit-config.js +++ b/src/componentconfig/edit-config.js @@ -20,7 +20,6 @@ import {FormGroup, FormControl, FormLabel} from 'react-bootstrap'; import { Multiselect } from 'multiselect-react-dropdown' import Dialog from '../common/dialogs/dialog'; import ParametersEditor from '../common/parameters-editor'; -import SelectFile from "../file/select-file"; class EditConfigDialog extends React.Component { valid = false; From a20dff47a9fe54380fc230605fbce8658ada67c6 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Tue, 7 Jul 2020 21:34:21 +0200 Subject: [PATCH 03/30] wip: adding tooltips , cosmetic changes #235 --- src/common/table.js | 11 +++--- src/dashboard/dashboard-button-group.js | 48 ++++++++++++++++--------- src/dashboard/dashboard.js | 1 - src/widget/toolbox-item.js | 2 +- src/widget/widget-toolbox.js | 9 +++-- 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/common/table.js b/src/common/table.js index d68191a..87a52be 100644 --- a/src/common/table.js +++ b/src/common/table.js @@ -17,7 +17,7 @@ import React, { Component } from 'react'; import _ from 'lodash'; -import { Table, Button, FormControl, FormLabel, FormCheck } from 'react-bootstrap'; +import { Table, Button, FormControl, FormLabel, FormCheck, Tooltip, OverlayTrigger } from 'react-bootstrap'; import { Link } from 'react-router-dom'; import Icon from './icon'; @@ -103,11 +103,13 @@ class CustomTable extends Component { // add buttons if (child.props.editButton) { - cell.push(); + cell.push( Edit } > + ); } if (child.props.deleteButton) { - cell.push(); + cell.push( Delete } > + ); } if (child.props.checkbox) { @@ -117,7 +119,8 @@ class CustomTable extends Component { } if (child.props.exportButton) { - cell.push(); + cell.push( Export } > + ); } return cell; diff --git a/src/dashboard/dashboard-button-group.js b/src/dashboard/dashboard-button-group.js index 8baeece..b18e5b3 100644 --- a/src/dashboard/dashboard-button-group.js +++ b/src/dashboard/dashboard-button-group.js @@ -17,13 +17,13 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { Button } from 'react-bootstrap'; +import { Button,OverlayTrigger, Tooltip } from 'react-bootstrap'; import Icon from "../common/icon"; class DashboardButtonGroup extends React.Component { render() { const buttonStyle = { - marginLeft: '8px' + marginLeft: '12px', }; const buttons = []; @@ -35,46 +35,60 @@ class DashboardButtonGroup extends React.Component { if (this.props.editing) { buttons.push( - , - + , + Discard changes } > + + ); } else { if (this.props.fullscreen !== true) { buttons.push( - + ); } if (this.props.paused) { buttons.push( - + ); } else { buttons.push( - + ); } buttons.push( - + ); buttons.push( - + ); } diff --git a/src/dashboard/dashboard.js b/src/dashboard/dashboard.js index 05f69e1..e45d6aa 100644 --- a/src/dashboard/dashboard.js +++ b/src/dashboard/dashboard.js @@ -240,7 +240,6 @@ class Dashboard extends Component { closeEditFiles(){ this.setState({ filesEditModal: false }); - // TODO do we need this if the dispatches happen in the dialog? } closeEdit(data){ diff --git a/src/widget/toolbox-item.js b/src/widget/toolbox-item.js index b61bdc4..4703aee 100644 --- a/src/widget/toolbox-item.js +++ b/src/widget/toolbox-item.js @@ -51,7 +51,7 @@ class ToolboxItem extends React.Component { if (this.props.disabled === false) { return this.props.connectDragSource(
- + {this.props.icon && } {this.props.name} diff --git a/src/widget/widget-toolbox.js b/src/widget/widget-toolbox.js index 18912f1..b2fb527 100644 --- a/src/widget/widget-toolbox.js +++ b/src/widget/widget-toolbox.js @@ -54,6 +54,11 @@ class WidgetToolbox extends React.Component { + Drag and drop widgets onto the dashboard } > + +
@@ -65,12 +70,12 @@ class WidgetToolbox extends React.Component {
Increase dashboard height } > - Decrease dashboard height } > - From f3f58696caa349b03720b67e3d67d369889ba1a2 Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Tue, 7 Jul 2020 21:37:46 +0200 Subject: [PATCH 04/30] edit files button added to scenario page #219 --- src/scenario/scenario.js | 41 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 8d3495e..0b9df12 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -17,7 +17,7 @@ import React from 'react'; import { Container } from 'flux/utils'; -import { Button, InputGroup, FormControl } from 'react-bootstrap'; +import { Button, InputGroup, FormControl, Tooltip, OverlayTrigger } from 'react-bootstrap'; import FileSaver from 'file-saver'; @@ -35,6 +35,7 @@ import TableColumn from '../common/table-column'; import ImportConfigDialog from '../componentconfig/import-config'; import ImportDashboardDialog from "../dashboard/import-dashboard"; import NewDashboardDialog from "../dashboard/new-dashboard"; +import EditFiles from '../file/edit-files' import ICAction from '../ic/ic-action'; import DeleteDialog from '../common/dialogs/delete-dialog'; @@ -93,6 +94,8 @@ class Scenario extends React.Component { modalConfigData: (prevState.modalConfigData !== {} && prevState.modalConfigData !== undefined )? prevState.modalConfigData : {}, selectedConfigs: [], modalConfigIndex: 0, + filesEditModal: prevState.filesEditModal || false, + filesEditSaveState: prevState.filesEditSaveState || [], editOutputSignalsModal: prevState.editOutputSignalsModal || false, editInputSignalsModal: prevState.editInputSignalsModal || false, @@ -391,6 +394,24 @@ class Scenario extends React.Component { this.setState({editOutputSignalsModal: false}); } } + + onEditFiles(){ + console.log("here r the files in scenario:"); + console.log(this.state.file); + let tempFiles = []; + this.state.files.forEach( file => { + tempFiles.push({ + id: file.id, + name: file.name + }); + }) + this.setState({filesEditModal: true, filesEditSaveState: tempFiles}); + } + + closeEditFiles(){ + this.setState({ filesEditModal: false }); + // TODO do we need this if the dispatches happen in the dialog? + } /* ############################################## * File modification methods @@ -419,8 +440,24 @@ class Scenario extends React.Component { } return
+
+ Add, edit or delete files of scenario } > + + +

{this.state.scenario.name}

+ + {/*Component Configurations table*/} @@ -443,7 +480,7 @@ class Scenario extends React.Component { /> this.getICName(icID)} /> Date: Wed, 8 Jul 2020 14:49:59 +0200 Subject: [PATCH 05/30] fix for widgets that use signals in case no signal is selected --- src/widget/widgets/gauge.js | 166 ++++++++++++++++++----------------- src/widget/widgets/input.js | 12 +-- src/widget/widgets/lamp.js | 29 +++--- src/widget/widgets/slider.js | 10 ++- src/widget/widgets/value.js | 46 +++++----- 5 files changed, 138 insertions(+), 125 deletions(-) diff --git a/src/widget/widgets/gauge.js b/src/widget/widgets/gauge.js index 3aa3e3b..629784e 100644 --- a/src/widget/widgets/gauge.js +++ b/src/widget/widgets/gauge.js @@ -81,114 +81,116 @@ class WidgetGauge extends Component { // get the signal with the selected signal ID let signalID = props.widget.signalIDs[0]; let signal = props.signals.filter(s => s.id === signalID) - // determine ID of infrastructure component related to signal[0] (there is only one signal for a lamp widget) - let icID = props.icIDs[signal[0].id]; - let returnState = {} + if(signal.length > 0) { + // determine ID of infrastructure component related to signal[0] (there is only one signal for a lamp widget) + let icID = props.icIDs[signal[0].id]; - returnState["colorZones"] = props.widget.customProperties.zones; + let returnState = {} - if(signalID){ - returnState["signalID"] = signalID; - } - // Update unit (assuming there is exactly one signal for this widget) - if(signal !== undefined){ - returnState["unit"] = signal[0].unit; - } + returnState["colorZones"] = props.widget.customProperties.zones; - // update value + if (signalID) { + returnState["signalID"] = signalID; + } + // Update unit (assuming there is exactly one signal for this widget) + if (signal !== undefined) { + returnState["unit"] = signal[0].unit; + } - // check if data available - if (props.data == null - || props.data[icID] == null - || props.data[icID].output == null - || props.data[icID].output.values == null) { - return{ value: 0, minValue: 0, maxValue: 10}; - } + // update value - // memorize if min or max value is updated - let updateValue = false; - let updateMinValue = false; - let updateMaxValue = false; + // check if data available + if (props.data == null + || props.data[icID] == null + || props.data[icID].output == null + || props.data[icID].output.values == null) { + return {value: 0, minValue: 0, maxValue: 10}; + } - // check if value has changed - const data = props.data[icID].output.values[signal[0].index-1]; - // Take just 3 decimal positions - // Note: Favor this method over Number.toFixed(n) in order to avoid a type conversion, since it returns a String - if (data != null) { - const value = signal[0].scalingFactor * Math.round(data[data.length - 1].y * 1e3) / 1e3; - let minValue = null; - let maxValue = null; + // memorize if min or max value is updated + let updateValue = false; + let updateMinValue = false; + let updateMaxValue = false; - if ((state.value !== value && value != null) || props.widget.customProperties.valueUseMinMax || state.useMinMaxChange) { - //value has changed - updateValue = true; + // check if value has changed + const data = props.data[icID].output.values[signal[0].index - 1]; + // Take just 3 decimal positions + // Note: Favor this method over Number.toFixed(n) in order to avoid a type conversion, since it returns a String + if (data != null) { + const value = signal[0].scalingFactor * Math.round(data[data.length - 1].y * 1e3) / 1e3; + let minValue = null; + let maxValue = null; - // update min-max if needed - let updateLabels = false; + if ((state.value !== value && value != null) || props.widget.customProperties.valueUseMinMax || state.useMinMaxChange) { + //value has changed + updateValue = true; - minValue = state.minValue; - maxValue = state.maxValue; + // update min-max if needed + let updateLabels = false; - if (minValue == null || (!props.widget.customProperties.valueUseMinMax && (value < minValue || signalID !== state.signalID)) ||state.useMinMaxChange) { - minValue = value - 0.5; - updateLabels = true; - updateMinValue = true; - } + minValue = state.minValue; + maxValue = state.maxValue; - if (maxValue == null || (!props.widget.customProperties.valueUseMinMax && (value > maxValue || signalID !== state.signalID)) || state.useMinMaxChange) { - maxValue = value + 0.5; - updateLabels = true; - updateMaxValue = true; - returnState["useMinMaxChange"] = false; - } + if (minValue == null || (!props.widget.customProperties.valueUseMinMax && (value < minValue || signalID !== state.signalID)) || state.useMinMaxChange) { + minValue = value - 0.5; + updateLabels = true; + updateMinValue = true; + } - if (props.widget.customProperties.valueUseMinMax) { + if (maxValue == null || (!props.widget.customProperties.valueUseMinMax && (value > maxValue || signalID !== state.signalID)) || state.useMinMaxChange) { + maxValue = value + 0.5; + updateLabels = true; + updateMaxValue = true; + returnState["useMinMaxChange"] = false; + } + + if (props.widget.customProperties.valueUseMinMax) { minValue = props.widget.customProperties.valueMin; updateMinValue = true; maxValue = props.widget.customProperties.valueMax; updateMaxValue = true; updateLabels = true; - } - - if (updateLabels === false && state.gauge) { - // check if min/max changed - if (minValue > state.gauge.minValue) { - minValue = state.gauge.minValue; - updateMinValue = true; } - if (maxValue < state.gauge.maxValue) { - maxValue = state.gauge.maxValue; - updateMaxValue = true; + if (updateLabels === false && state.gauge) { + // check if min/max changed + if (minValue > state.gauge.minValue) { + minValue = state.gauge.minValue; + updateMinValue = true; + } + + if (maxValue < state.gauge.maxValue) { + maxValue = state.gauge.maxValue; + updateMaxValue = true; + } } } - } - if(props.widget.customProperties.valueUseMinMax !== state.useMinMax){ - returnState["useMinMax"] = props.widget.customProperties.valueUseMinMax; - } + if (props.widget.customProperties.valueUseMinMax !== state.useMinMax) { + returnState["useMinMax"] = props.widget.customProperties.valueUseMinMax; + } - // prepare returned state - if(updateValue === true){ - returnState["value"] = value; - } - if(updateMinValue === true){ - returnState["minValue"] = minValue; - } - if(updateMaxValue === true){ - returnState["maxValue"] = maxValue; - } - - if (returnState !== {}){ - return returnState; - } - else{ - return null; - } - } // if there is signal data + // prepare returned state + if (updateValue === true) { + returnState["value"] = value; + } + if (updateMinValue === true) { + returnState["minValue"] = minValue; + } + if (updateMaxValue === true) { + returnState["maxValue"] = maxValue; + } + if (returnState !== {}) { + return returnState; + } else { + return null; + } + } // if there is signal data + } + return null; } diff --git a/src/widget/widgets/input.js b/src/widget/widgets/input.js index 0b87617..142f4e2 100644 --- a/src/widget/widgets/input.js +++ b/src/widget/widgets/input.js @@ -42,11 +42,13 @@ class WidgetInput extends Component { value = Number(props.widget.customProperties.default_value) } - // Update unit (assuming there is exactly one signal for this widget) - let signalID = props.widget.signalIDs[0]; - let signal = props.signals.find(sig => sig.id === signalID); - if(signal !== undefined){ - unit = signal.unit; + if (props.widget.signalIDs.length > 0) { + // Update unit (assuming there is exactly one signal for this widget) + let signalID = props.widget.signalIDs[0]; + let signal = props.signals.find(sig => sig.id === signalID); + if (signal !== undefined) { + unit = signal.unit; + } } if (unit !== '' && value !== ''){ diff --git a/src/widget/widgets/lamp.js b/src/widget/widgets/lamp.js index c0ca9a0..c6fd5e6 100644 --- a/src/widget/widgets/lamp.js +++ b/src/widget/widgets/lamp.js @@ -36,21 +36,24 @@ class WidgetLamp extends Component { // get the signal with the selected signal ID let signalID = props.widget.signalIDs[0]; let signal = props.signals.filter(s => s.id === signalID) - // determine ID of infrastructure component related to signal[0] (there is only one signal for a lamp widget) - let icID = props.icIDs[signal[0].id]; - // check if data available - if (props.data == null - || props.data[icID] == null - || props.data[icID].output == null - || props.data[icID].output.values == null) { - return{value:''}; - } + if(signal.length>0) { + // determine ID of infrastructure component related to signal[0] (there is only one signal for a lamp widget) + let icID = props.icIDs[signal[0].id]; - // check if value has changed - const data = props.data[icID].output.values[signal[0].index-1]; - if (data != null && Number(state.value) !== signal[0].scalingFactor * data[data.length - 1].y) { - return { value: signal[0].scalingFactor * data[data.length - 1].y }; + // check if data available + if (props.data == null + || props.data[icID] == null + || props.data[icID].output == null + || props.data[icID].output.values == null) { + return {value: ''}; + } + + // check if value has changed + const data = props.data[icID].output.values[signal[0].index - 1]; + if (data != null && Number(state.value) !== signal[0].scalingFactor * data[data.length - 1].y) { + return {value: signal[0].scalingFactor * data[data.length - 1].y}; + } } return null; diff --git a/src/widget/widgets/slider.js b/src/widget/widgets/slider.js index 10bb055..8e7e2ff 100644 --- a/src/widget/widgets/slider.js +++ b/src/widget/widgets/slider.js @@ -53,10 +53,12 @@ class WidgetSlider extends Component { } // Update unit (assuming there is exactly one signal for this widget) - let signalID = props.widget.signalIDs[0]; - let signal = props.signals.find(sig => sig.id === signalID); - if(signal !== undefined){ - unit = signal.unit; + if (props.widget.signalIDs.length > 0) { + let signalID = props.widget.signalIDs[0]; + let signal = props.signals.find(sig => sig.id === signalID); + if (signal !== undefined) { + unit = signal.unit; + } } if (unit !== '' && value !== ''){ diff --git a/src/widget/widgets/value.js b/src/widget/widgets/value.js index 8c4c5a9..482a94f 100644 --- a/src/widget/widgets/value.js +++ b/src/widget/widgets/value.js @@ -36,31 +36,35 @@ class WidgetValue extends Component { // get the signal with the selected signal ID let signalID = props.widget.signalIDs[0]; let signal = props.signals.filter(s => s.id === signalID) - // determine ID of infrastructure component related to signal[0] (there is only one signal for a value widget) - let icID = props.icIDs[signal[0].id]; + if(signal.length>0) { + // determine ID of infrastructure component related to signal[0] (there is only one signal for a value widget) + let icID = props.icIDs[signal[0].id]; - // check if data available - let value = '' - if (props.data == null || props.data[icID] == null || props.data[icID].output == null || props.data[icID].output.values == null) { - value = ''; - } else { - // check if value has changed - const data = props.data[icID].output.values[signal[0].index - 1]; - if (data != null && Number(state.value) !== data[data.length - 1].y) { - value = signal[0].scalingFactor * data[data.length - 1].y; + // check if data available + let value = '' + if (props.data == null || props.data[icID] == null || props.data[icID].output == null || props.data[icID].output.values == null) { + value = ''; + } else { + // check if value has changed + const data = props.data[icID].output.values[signal[0].index - 1]; + if (data != null && Number(state.value) !== data[data.length - 1].y) { + value = signal[0].scalingFactor * data[data.length - 1].y; + } } + + // Update unit (assuming there is exactly one signal for this widget) + let unit = ''; + if (signal !== undefined) { + unit = signal[0].unit; + } + + return { + value: value, + unit: unit, + }; } - // Update unit (assuming there is exactly one signal for this widget) - let unit = ''; - if(signal !== undefined){ - unit = signal[0].unit; - } - - return { - value: value, - unit: unit, - }; + return null; } From bb09c691f876cab3a18548a6b8b5b093893aae95 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 8 Jul 2020 15:42:40 +0200 Subject: [PATCH 06/30] generalize edit file control --- src/widget/edit-widget/edit-widget-file-control.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/edit-widget/edit-widget-file-control.js b/src/widget/edit-widget/edit-widget-file-control.js index a55aa23..21868ce 100644 --- a/src/widget/edit-widget/edit-widget-file-control.js +++ b/src/widget/edit-widget/edit-widget-file-control.js @@ -49,7 +49,7 @@ class EditFileWidgetControl extends React.Component { let fileOptions = []; if (this.state.files.length > 0){ fileOptions.push( - + ) fileOptions.push(this.state.files.map((file, index) => ( @@ -60,7 +60,7 @@ class EditFileWidgetControl extends React.Component { return
- Image + File Date: Wed, 8 Jul 2020 15:44:01 +0200 Subject: [PATCH 07/30] widget edit dialog remains open even if widget component is updated in the meantime --- src/dashboard/dashboard.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dashboard/dashboard.js b/src/dashboard/dashboard.js index e45d6aa..9c3590b 100644 --- a/src/dashboard/dashboard.js +++ b/src/dashboard/dashboard.js @@ -112,7 +112,7 @@ class Dashboard extends Component { return ICused; }); } - + return { dashboard, widgets, @@ -125,7 +125,7 @@ class Dashboard extends Component { editing: prevState.editing || false, paused: prevState.paused || false, - editModal: false, + editModal: prevState.editModal || false, filesEditModal: prevState.filesEditModal || false, filesEditSaveState: prevState.filesEditSaveState || [], modalData: null, From 9303b0b2c2d92dcc2235cf076945fe2845038b2b Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 8 Jul 2020 15:45:57 +0200 Subject: [PATCH 08/30] Fixing edit of Topology window, file changes work now #217 --- src/widget/widgets/topology.js | 90 ++++++++++++++++------------------ 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/src/widget/widgets/topology.js b/src/widget/widgets/topology.js index 8aad399..1eb64fc 100644 --- a/src/widget/widgets/topology.js +++ b/src/widget/widgets/topology.js @@ -65,19 +65,12 @@ function show(element) { if(element !== undefined) { element.style.visibility = 'inherit'; } - else{ - console.log("MouseOver, show, element undefined.") - } } function hide(element) { if (element !== undefined) { element.style.visibility = 'hidden'; - } else { - console.log("MouseLeave, hide, element undefined.") } - - } // De-initialize functions @@ -91,25 +84,45 @@ class WidgetTopology extends React.Component { super(props); this.svgElem = React.createRef(); this.Viewer = null; - this.dashboardState = 'initial' - this.message = '' - let file = this.props.files.find(file => file.id === parseInt(this.props.widget.customProperties.file, 10)); this.state = { - file: file + file: this.props.files.find(file => file.id === parseInt(this.props.widget.customProperties.file, 10)), + dashboardState: 'initial', + message: '' }; } static getDerivedStateFromProps(props, state){ + // find the selected file of the widget, is undefined if no file is selected let file = props.files.find(file => file.id === parseInt(props.widget.customProperties.file, 10)); - if (state.file === undefined || state.file.id !== file.id) { - return{ - file: file - }; + let dashboardState = state.dashboardState; + let message = state.message; + + if(file === undefined){ + dashboardState = 'show_message'; + message = 'Select a topology model.' + } else if (!file.hasOwnProperty('data') && dashboardState === 'show_message'){ + // data of file is missing, start download + dashboardState = 'loading'; + message = ''; + AppDispatcher.dispatch({ + type: 'files/start-download', + data: file.id, + token: props.token + }); + } else if (file.hasOwnProperty('data') && (dashboardState === 'loading'|| dashboardState === 'show_message')){ + //file is available set state to ready + dashboardState = 'ready' + message = ''; } - return null + + return{ + file: file, + dashboardState:dashboardState, + message: message, + }; } componentDidMount() { @@ -124,13 +137,12 @@ class WidgetTopology extends React.Component { //this.Viewer.fitToViewer(); - // Query the file referenced by the widget - let widgetFile = parseInt(this.props.widget.customProperties.file, 10); - if (widgetFile !== -1 && this.state.file === undefined) { - this.dashboardState = 'loading'; + // Query the file referenced by the widget (if any) + if (this.state.file !== undefined) { + this.setState({dashboardState: 'loading'}); AppDispatcher.dispatch({ type: 'files/start-download', - data: widgetFile, + data: this.state.file.id, token: this.props.token }); } @@ -142,43 +154,25 @@ class WidgetTopology extends React.Component { componentDidUpdate(prevProps: Readonly

, prevState: Readonly, snapshot: SS): void { - if(this.state.file === undefined) { - // No file has been selected - this.dashboardState = 'show_message'; - this.message = 'Select a topology model first.'; - return; - } - - if((prevState.file === undefined && this.state.file !== undefined) - || (this.state.file.id !== prevState.file.id && this.state.file.id !== -1)) { - // if file has changed, download new file - this.dashboardState = 'loading'; - AppDispatcher.dispatch({ - type: 'files/start-download', - data: this.state.file.id, - token: this.props.token - }); - } else if (this.state.file.hasOwnProperty("data") && this.dashboardState === 'loading') { - // data of file has been newly downloaded (did not exist in previous state) - this.dashboardState = 'ready'; - - } else if(this.state.file.hasOwnProperty("data") && this.dashboardState === 'ready'){ + if(this.state.dashboardState === 'ready'){ + //Topology file incl data downloaded, init SVG (should happen only once!) if (this.svgElem) { let cimsvgInstance = new cimsvg(this.svgElem.current); cimsvg.setCimsvg(cimsvgInstance); cimsvgInstance.setFileCount(1); // transform data blob into string format this.state.file.data.text().then(function(content) { - cimsvgInstance.loadFile(content); - cimsvgInstance.fit(); - attachComponentEvents(); + cimsvgInstance.loadFile(content); + cimsvgInstance.fit(); + attachComponentEvents(); }); + this.setState({dashboardState: 'loaded'}); } else { console.error("The svgElem variable is not initialized before the attempt to create the cimsvg instance."); } - } + } } render() { @@ -192,11 +186,11 @@ class WidgetTopology extends React.Component { position: "right" } - switch(this.dashboardState) { + switch(this.state.dashboardState) { case 'loading': markup =

; break; case 'show_message': - markup =
{ this.message }
; break; + markup =
{ this.state.message }
; break; default: markup = (
Date: Wed, 8 Jul 2020 16:41:55 +0200 Subject: [PATCH 09/30] Add edit button to model file column, prepare placeholder for Pintura start #234 --- src/scenario/scenario.js | 51 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 8e2ceda..59b7804 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -396,14 +396,18 @@ class Scenario extends React.Component { * File modification methods ############################################## */ - getListOfFiles(fileIDs, type) { + getListOfFiles(fileIDs, types) { let fileList = ''; for (let id of fileIDs){ for (let file of this.state.files) { - if (file.id === id && (type === 'all' || file.type.includes(type))) { - fileList = fileList + '\n' + file.name; + if (file.id === id && types.some(e => file.type.includes(e))) { + if (fileList === ''){ + fileList = file.name + } else { + fileList = fileList + ';' + file.name; + } } } } @@ -414,6 +418,37 @@ class Scenario extends React.Component { return fileList; } + startPintura(configIndex){ + let config = this.state.configs[configIndex]; + + // get xml / CIM file + let files = [] + for (let id of config.fileIDs){ + for (let file of this.state.files) { + if (file.id === id && ['xml'].some(e => file.type.includes(e))) { + files.push(file); + } + } + } + + if(files.length > 1){ + // more than one CIM file... + console.warn("There is more than one CIM file selected in this component configuration. I will open them all in a separate tab.") + } + + let base_host = 'aaa.bbb.ccc.ddd/api/v2/files/' + for (let file of files) { + // endpoint param serves for download and upload of CIM file, token is required for authentication + let params = { + token: this.state.sessionToken, + endpoint: base_host + String(file.id), + } + + // TODO start Pintura for editing CIM/ XML file from here + console.warn("Starting Pintura... and nothing happens so far :-) ", params) + } + } + /* ############################################## * Render method ############################################## */ @@ -438,8 +473,14 @@ class Scenario extends React.Component {
this.onConfigChecked(index, event)} width='30' /> - this.getListOfFiles(fileIDs, 'all')} /> - this.getListOfFiles(fileIDs, 'xml')} /> + this.getListOfFiles(fileIDs, ['json', 'JSON'])} /> + this.getListOfFiles(fileIDs, ['xml'])} + editButton + onEdit={(index) => this.startPintura(index)} + /> Date: Wed, 8 Jul 2020 17:02:29 +0200 Subject: [PATCH 10/30] Fix Dropdown Item import --- src/ic/ic-action.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ic/ic-action.js b/src/ic/ic-action.js index 6a9e591..51d2cd2 100644 --- a/src/ic/ic-action.js +++ b/src/ic/ic-action.js @@ -16,7 +16,7 @@ ******************************************************************************/ import React from 'react'; -import { Button, ButtonToolbar, DropdownButton, DropdownItem } from 'react-bootstrap'; +import { Button, ButtonToolbar, DropdownButton, Dropdown } from 'react-bootstrap'; class ICAction extends React.Component { constructor(props) { @@ -49,9 +49,9 @@ class ICAction extends React.Component { render() { const actionList = this.props.actions.map(action => ( - + {action.title} - + )); return
From 564906cf252eed4206a0e8e29a17668cbe3809b6 Mon Sep 17 00:00:00 2001 From: irismarie Date: Wed, 8 Jul 2020 17:50:41 +0200 Subject: [PATCH 11/30] corrected grid snapping, solves #232 notes: -was already snapping to grid but didn't look like it because toolbox border was shifting everything by 3px -drag function wasn't updating the position, this.rnd.updatePosition doesn't work inside onDrag -snapping while dragging is done by dragGrid property --- src/styles/app.css | 2 +- src/widget/editable-widget-container.js | 18 +++++------------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/styles/app.css b/src/styles/app.css index 797512a..98888f1 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -305,7 +305,7 @@ body { } .toolbox-dropzone-editing { - border: 3px dashed #e1e1e1; + outline: 3px dashed #e1e1e1; } .toolbox-dropzone-active { diff --git a/src/widget/editable-widget-container.js b/src/widget/editable-widget-container.js index 5ac2a55..91f691d 100644 --- a/src/widget/editable-widget-container.js +++ b/src/widget/editable-widget-container.js @@ -31,7 +31,6 @@ class EditableWidgetContainer extends React.Component { if (this.props.grid === 1) { return value; } - return Math.round(value / this.props.grid) * this.props.grid; } @@ -41,28 +40,22 @@ class EditableWidgetContainer extends React.Component { } }; - drag = (event, data) => { - const x = this.snapToGrid(data.x); - const y = this.snapToGrid(data.y); - - if (x !== data.x || y !== data.y) { - this.rnd.updatePosition({ x, y }); - } - }; - dragStop = (event, data) => { const widget = this.props.widget; - widget.x = this.snapToGrid(data.x); widget.y = this.snapToGrid(data.y); + + if (widget.x !== data.x || widget.y !== data.y) { + this.rnd.updatePosition({ x: widget.x, y: widget.y}); + } + if (this.props.onWidgetChange != null) { this.props.onWidgetChange(widget, this.props.index); } }; resizeStop = (event, direction, ref,delta, position) => { - const widget = this.props.widget; // resize depends on direction @@ -119,7 +112,6 @@ class EditableWidgetContainer extends React.Component { className={widgetClasses} onResizeStart={this.borderWasClicked} onResizeStop={this.resizeStop} - onDrag={this.drag} onDragStop={this.dragStop} dragGrid={gridArray} resizeGrid={gridArray} From ed26cd16fd217edfc4504b3e29c06367a083eab3 Mon Sep 17 00:00:00 2001 From: irismarie Date: Thu, 9 Jul 2020 15:58:39 +0200 Subject: [PATCH 12/30] delete unused function --- src/scenario/scenarios.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/scenario/scenarios.js b/src/scenario/scenarios.js index 87aa7e5..63432ce 100644 --- a/src/scenario/scenarios.js +++ b/src/scenario/scenarios.js @@ -117,19 +117,6 @@ class Scenarios extends Component { }); }; - showEditModal(id) { - // get scenario by id - var editScenario; - - this.state.scenarios.forEach((scenario) => { - if (scenario.id === id) { - editScenario = scenario; - } - }); - - this.setState({ editModal: true, modalScenario: editScenario }); - } - closeEditModal(data) { this.setState({ editModal: false }); From 5567bb433ccc94a57ce12bf4dc4bd77c0253ce9f Mon Sep 17 00:00:00 2001 From: irismarie Date: Thu, 9 Jul 2020 16:04:38 +0200 Subject: [PATCH 13/30] edit dashboard name, closes #233 --- src/dashboard/edit-dashboard.js | 6 +++--- src/scenario/scenario.js | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/dashboard/edit-dashboard.js b/src/dashboard/edit-dashboard.js index 7de6012..900a6c8 100644 --- a/src/dashboard/edit-dashboard.js +++ b/src/dashboard/edit-dashboard.js @@ -21,14 +21,14 @@ import { FormGroup, FormControl, FormLabel } from 'react-bootstrap'; import Dialog from '../common/dialogs/dialog'; class EditDashboardDialog extends React.Component { - valid: false; + valid = true; constructor(props) { super(props); this.state = { name: '', - _id: '' + id: '' } } @@ -49,7 +49,7 @@ class EditDashboardDialog extends React.Component { resetState() { this.setState({ name: this.props.dashboard.name, - _id: this.props.dashboard._id + id: this.props.dashboard.id }); } diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 615f0ed..1155aa1 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -35,6 +35,7 @@ import TableColumn from '../common/table-column'; import ImportConfigDialog from '../componentconfig/import-config'; import ImportDashboardDialog from "../dashboard/import-dashboard"; import NewDashboardDialog from "../dashboard/new-dashboard"; +import EditDashboardDialog from '../dashboard/edit-dashboard'; import EditFiles from '../file/edit-files' import ICAction from '../ic/ic-action'; @@ -101,6 +102,7 @@ class Scenario extends React.Component { editInputSignalsModal: prevState.editInputSignalsModal || false, newDashboardModal: false, + dashboardEditModal: prevState.dashboardEditModal || false, deleteDashboardModal: false, importDashboardModal: false, modalDashboardData: {}, @@ -336,6 +338,21 @@ class Scenario extends React.Component { } } + closeEditDashboardModal(data) { + this.setState({ dashboardEditModal: false }); + + let editDashboard = this.state.modalDashboardData; + + if (data != null) { + editDashboard.name = data.name; + AppDispatcher.dispatch({ + type: 'dashboards/start-edit', + data: editDashboard, + token: this.state.sessionToken + }); + } + } + closeDeleteDashboardModal(confirmDelete) { this.setState({ deleteDashboardModal: false }); @@ -600,8 +617,10 @@ class Scenario extends React.Component { this.setState({ dashboardEditModal: true, modalDashboardData: this.state.dashboards[index] })} onDelete={(index) => this.setState({ deleteDashboardModal: true, modalDashboardData: this.state.dashboards[index], modalDashboardIndex: index })} onExport={index => this.exportDashboard(index)} /> @@ -615,6 +634,7 @@ class Scenario extends React.Component {
this.closeNewDashboardModal(data)} /> + this.closeEditDashboardModal(data)} /> this.closeImportDashboardModal(data)} /> this.closeDeleteDashboardModal(e)} /> From 51fafbf61b4ca2927e128cb1b1d3504f67ad43fe Mon Sep 17 00:00:00 2001 From: irismarie Date: Fri, 10 Jul 2020 13:08:24 +0200 Subject: [PATCH 14/30] added padding, closes #244 --- src/widget/toolbox-item.js | 4 ++-- src/widget/widget-toolbox.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/widget/toolbox-item.js b/src/widget/toolbox-item.js index 4703aee..7df6cfc 100644 --- a/src/widget/toolbox-item.js +++ b/src/widget/toolbox-item.js @@ -51,7 +51,7 @@ class ToolboxItem extends React.Component { if (this.props.disabled === false) { return this.props.connectDragSource(
- + {this.props.icon && } {this.props.name} @@ -61,7 +61,7 @@ class ToolboxItem extends React.Component { else { return (
- + {this.props.icon && } {this.props.name} diff --git a/src/widget/widget-toolbox.js b/src/widget/widget-toolbox.js index b2fb527..04e8492 100644 --- a/src/widget/widget-toolbox.js +++ b/src/widget/widget-toolbox.js @@ -70,7 +70,7 @@ class WidgetToolbox extends React.Component {
Increase dashboard height } > - From b7a1ec106b39ed97d3b5293886163dcdff999fbf Mon Sep 17 00:00:00 2001 From: irismarie Date: Fri, 10 Jul 2020 16:38:04 +0200 Subject: [PATCH 15/30] remove text from input after submitting (scenario user), closes #237 --- src/scenario/scenario.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 1155aa1..09f8712 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -107,6 +107,7 @@ class Scenario extends React.Component { importDashboardModal: false, modalDashboardData: {}, + userToAdd: '', deleteUserName: '', deleteUserModal: false, } @@ -139,13 +140,19 @@ class Scenario extends React.Component { * User modification methods ############################################## */ + onUserInputChange(e) { + this.setState({userToAdd: e.target.value}); + } + addUser() { AppDispatcher.dispatch({ type: 'scenarios/add-user', data: this.state.scenario.id, - username: this.userToAdd, + username: this.state.userToAdd, token: this.state.sessionToken }); + + this.setState({userToAdd: ''}); } closeDeleteUserModal() { @@ -657,7 +664,9 @@ class Scenario extends React.Component { this.userToAdd = e.target.value} + onChange={(e) => this.onUserInputChange(e)} + value={this.state.userToAdd} + type="text" /> , Discard changes } > ); @@ -51,7 +59,7 @@ class DashboardButtonGroup extends React.Component { buttons.push( Change to fullscreen view } > ); @@ -61,7 +69,7 @@ class DashboardButtonGroup extends React.Component { buttons.push( Continue simulation } > ); @@ -69,7 +77,7 @@ class DashboardButtonGroup extends React.Component { buttons.push( Pause simulation } > ); @@ -78,7 +86,7 @@ class DashboardButtonGroup extends React.Component { buttons.push( Add, edit or delete files of scenario } > ); @@ -86,7 +94,7 @@ class DashboardButtonGroup extends React.Component { buttons.push( Add widgets and edit layout } > ); diff --git a/src/ic/ic-action.js b/src/ic/ic-action.js index 51d2cd2..80c60e0 100644 --- a/src/ic/ic-action.js +++ b/src/ic/ic-action.js @@ -16,7 +16,7 @@ ******************************************************************************/ import React from 'react'; -import { Button, ButtonToolbar, DropdownButton, Dropdown } from 'react-bootstrap'; +import { Button, ButtonToolbar, DropdownButton, Dropdown, Tooltip, OverlayTrigger } from 'react-bootstrap'; class ICAction extends React.Component { constructor(props) { @@ -48,6 +48,8 @@ class ICAction extends React.Component { }; render() { + let showTooltip = this.state.selectedAction.id === '-1'; + const actionList = this.props.actions.map(action => ( {action.title} @@ -55,14 +57,25 @@ class ICAction extends React.Component { )); return
- Send command to infrastructure component + {showTooltip ? + + Select command for infrastructure component } > + + {actionList} + + + Send command to infrastructure component } > + + + + : {actionList} - + }
; } } diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 09f8712..5b413f3 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -508,11 +508,17 @@ class Scenario extends React.Component { paddingTop: '30px' } + const iconStyle = { + color: '#007bff', + height: '25px', + width : '25px' + } + return
Add, edit or delete files of scenario } >
diff --git a/src/widget/toolbox-item.js b/src/widget/toolbox-item.js index 7df6cfc..f1ebb93 100644 --- a/src/widget/toolbox-item.js +++ b/src/widget/toolbox-item.js @@ -51,7 +51,7 @@ class ToolboxItem extends React.Component { if (this.props.disabled === false) { return this.props.connectDragSource(
- + {this.props.icon && } {this.props.name} diff --git a/src/widget/widget-toolbox.js b/src/widget/widget-toolbox.js index 04e8492..07c3a36 100644 --- a/src/widget/widget-toolbox.js +++ b/src/widget/widget-toolbox.js @@ -37,6 +37,12 @@ class WidgetToolbox extends React.Component { render() { // Only one topology widget at the time is supported + const iconStyle = { + color: '#007bff', + height: '25px', + width : '25px' + } + const thereIsTopologyWidget = this.props.widgets != null && Object.values(this.props.widgets).filter(w => w.type === 'Topology').length > 0; const topologyItemMsg = thereIsTopologyWidget? 'Currently only one is supported' : ''; @@ -70,13 +76,13 @@ class WidgetToolbox extends React.Component {
Increase dashboard height } > - Decrease dashboard height } > -
From b42425a0e5a81134c6ae496e2b35b3f5835fadd0 Mon Sep 17 00:00:00 2001 From: irismarie Date: Tue, 14 Jul 2020 15:51:48 +0200 Subject: [PATCH 17/30] added line widget (#206) --- src/styles/widgets.css | 11 ++++++ .../edit-widget-control-creator.js | 8 +++- src/widget/widget-factory.js | 7 ++++ src/widget/widget-toolbox.js | 1 + src/widget/widget.js | 6 +++ src/widget/widgets/line.js | 39 +++++++++++++++++++ 6 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/widget/widgets/line.js diff --git a/src/styles/widgets.css b/src/styles/widgets.css index 4a8c976..102a311 100644 --- a/src/styles/widgets.css +++ b/src/styles/widgets.css @@ -379,3 +379,14 @@ div[class*="-widget"] label { border: 2px solid lightgray; } /* End box widget */ + +/* Begin line widget */ +.line-widget { + width: 100%; + height: 1%; + border: 2px solid red; + transform: rotate(0deg); +} + + +/* End line widget */ diff --git a/src/widget/edit-widget/edit-widget-control-creator.js b/src/widget/edit-widget/edit-widget-control-creator.js index 2b656dc..1cf26ad 100644 --- a/src/widget/edit-widget/edit-widget-control-creator.js +++ b/src/widget/edit-widget/edit-widget-control-creator.js @@ -144,7 +144,6 @@ export default function CreateControls(widgetType = null, widget = null, session handleChange(e) } /> ); break; - case 'NumberInput': DialogControls.push( handleChange(e)} />, @@ -152,6 +151,13 @@ export default function CreateControls(widgetType = null, widget = null, session handleChange(e)} /> ); break; + case 'Line': + DialogControls.push( + handleChange(e)} />, + handleChange(e)} />, + handleChange(e)} /> + ); + break; default: console.log('Non-valid widget type: ' + widgetType); diff --git a/src/widget/widget-factory.js b/src/widget/widget-factory.js index 8b08117..285e2ed 100644 --- a/src/widget/widget-factory.js +++ b/src/widget/widget-factory.js @@ -180,6 +180,13 @@ class WidgetFactory { widget.height = 400; widget.customProperties.file = -1; // ID of file, -1 means non selected break; + case 'Line': + widget.height = 50; + widget.customProperties.border_color = 8; + WidgetSlider.customPropertier.border_width = 2; + widget.customProperties.margin_top = 15; + widget.customProperties.rotation = 0; + break; default: widget.width = 100; diff --git a/src/widget/widget-toolbox.js b/src/widget/widget-toolbox.js index 07c3a36..5236ece 100644 --- a/src/widget/widget-toolbox.js +++ b/src/widget/widget-toolbox.js @@ -53,6 +53,7 @@ class WidgetToolbox extends React.Component { + diff --git a/src/widget/widget.js b/src/widget/widget.js index e2faeb1..7b647db 100644 --- a/src/widget/widget.js +++ b/src/widget/widget.js @@ -43,6 +43,7 @@ import WidgetGauge from './widgets/gauge'; import WidgetBox from './widgets/box'; import WidgetHTML from './widgets/html'; import WidgetTopology from './widgets/topology'; +import WidgetLine from './widgets/line'; import '../styles/widgets.css'; @@ -221,6 +222,11 @@ class Widget extends React.Component { files={this.state.files} token={this.state.sessionToken} /> + } else if (widget.type === 'Line') { + return } return null; diff --git a/src/widget/widgets/line.js b/src/widget/widgets/line.js new file mode 100644 index 0000000..9ccc4eb --- /dev/null +++ b/src/widget/widgets/line.js @@ -0,0 +1,39 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React, { Component } from 'react'; + +import EditWidgetColorControl from '../edit-widget/edit-widget-color-control'; +import EditWidgetNumberControl from '../edit-widget/edit-widget-number-control'; + +class WidgetLine extends Component { + render() { + const lineStyle = { + borderColor: EditWidgetColorControl.ColorPalette[this.props.widget.customProperties.border_color], + transform: 'rotate(' + this.props.widget.customProperties.rotation + 'deg)', + borderWidth: '' + this.props.widget.customProperties.border_width + 'px' + }; + + return ( +
+ { } +
+ ); + } +} + +export default WidgetLine; From e628a5559305f81f6a74c6f53f094a53a4547dcb Mon Sep 17 00:00:00 2001 From: irismarie Date: Tue, 14 Jul 2020 16:02:15 +0200 Subject: [PATCH 18/30] fixed issue with line default value --- src/widget/widget-factory.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/widget/widget-factory.js b/src/widget/widget-factory.js index 285e2ed..ac2a8d8 100644 --- a/src/widget/widget-factory.js +++ b/src/widget/widget-factory.js @@ -181,9 +181,9 @@ class WidgetFactory { widget.customProperties.file = -1; // ID of file, -1 means non selected break; case 'Line': - widget.height = 50; - widget.customProperties.border_color = 8; - WidgetSlider.customPropertier.border_width = 2; + widget.height = 20; + widget.customProperties.border_color = 0; + widget.customProperties.border_width = 2; widget.customProperties.margin_top = 15; widget.customProperties.rotation = 0; break; From e1e9c61c64e28a4e891e13f3f372ebf44a30ce8d Mon Sep 17 00:00:00 2001 From: irismarie Date: Tue, 14 Jul 2020 16:47:25 +0200 Subject: [PATCH 19/30] increase default height so line can be edited more easily --- src/widget/widget-factory.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/widget-factory.js b/src/widget/widget-factory.js index ac2a8d8..0e16c84 100644 --- a/src/widget/widget-factory.js +++ b/src/widget/widget-factory.js @@ -181,7 +181,7 @@ class WidgetFactory { widget.customProperties.file = -1; // ID of file, -1 means non selected break; case 'Line': - widget.height = 20; + widget.height = 30; widget.customProperties.border_color = 0; widget.customProperties.border_width = 2; widget.customProperties.margin_top = 15; From 7a065ea5c567b9cc77f0eb0bab1305c7874f9521 Mon Sep 17 00:00:00 2001 From: irismarie Date: Tue, 14 Jul 2020 16:52:28 +0200 Subject: [PATCH 20/30] increase dialog size for signal editing, see #246 --- src/common/dialogs/dialog.js | 2 +- src/signal/edit-signal-mapping.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/dialogs/dialog.js b/src/common/dialogs/dialog.js index 9b3a2c8..4cc15af 100644 --- a/src/common/dialogs/dialog.js +++ b/src/common/dialogs/dialog.js @@ -46,7 +46,7 @@ class Dialog extends React.Component { render() { return ( - + {this.props.title} diff --git a/src/signal/edit-signal-mapping.js b/src/signal/edit-signal-mapping.js index 0c64108..59d2818 100644 --- a/src/signal/edit-signal-mapping.js +++ b/src/signal/edit-signal-mapping.js @@ -164,7 +164,8 @@ class EditSignalMapping extends React.Component { blendOutCancel = {true} onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} - valid={true}> + valid={true} + size='lg'> {this.props.direction} Mapping From b1d8c1fd390420295ea2defd195e5aea7ff77b14 Mon Sep 17 00:00:00 2001 From: irismarie Date: Tue, 14 Jul 2020 17:03:25 +0200 Subject: [PATCH 21/30] remove unused import --- src/widget/widgets/line.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widget/widgets/line.js b/src/widget/widgets/line.js index 9ccc4eb..680ca03 100644 --- a/src/widget/widgets/line.js +++ b/src/widget/widgets/line.js @@ -18,7 +18,6 @@ import React, { Component } from 'react'; import EditWidgetColorControl from '../edit-widget/edit-widget-color-control'; -import EditWidgetNumberControl from '../edit-widget/edit-widget-number-control'; class WidgetLine extends Component { render() { From 765a0a61afc9fd8bdaac93c4525ebdc522f73d51 Mon Sep 17 00:00:00 2001 From: irismarie Date: Tue, 14 Jul 2020 17:37:19 +0200 Subject: [PATCH 22/30] fix error, see #206 --- src/widget/edit-widget/edit-widget-control-creator.js | 2 +- src/widget/widget-factory.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/widget/edit-widget/edit-widget-control-creator.js b/src/widget/edit-widget/edit-widget-control-creator.js index 1cf26ad..b26bc04 100644 --- a/src/widget/edit-widget/edit-widget-control-creator.js +++ b/src/widget/edit-widget/edit-widget-control-creator.js @@ -155,7 +155,7 @@ export default function CreateControls(widgetType = null, widget = null, session DialogControls.push( handleChange(e)} />, handleChange(e)} />, - handleChange(e)} /> + handleChange(e)} /> ); break; diff --git a/src/widget/widget-factory.js b/src/widget/widget-factory.js index 0e16c84..3fe95e6 100644 --- a/src/widget/widget-factory.js +++ b/src/widget/widget-factory.js @@ -182,6 +182,7 @@ class WidgetFactory { break; case 'Line': widget.height = 30; + widget.width = 150; widget.customProperties.border_color = 0; widget.customProperties.border_width = 2; widget.customProperties.margin_top = 15; From 63ac373191ad3dd8e016ccc996e067232f7676e8 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 15 Jul 2020 11:18:29 +0200 Subject: [PATCH 23/30] time shows in plot edit dialog, closes #247 --- .../edit-widget/edit-widget-time-control.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/widget/edit-widget/edit-widget-time-control.js b/src/widget/edit-widget/edit-widget-time-control.js index 21b135d..23fb368 100644 --- a/src/widget/edit-widget/edit-widget-time-control.js +++ b/src/widget/edit-widget/edit-widget-time-control.js @@ -23,7 +23,7 @@ class EditWidgetTimeControl extends Component { super(props); this.state = { - widget: { + widget: { } }; } @@ -36,10 +36,23 @@ class EditWidgetTimeControl extends Component { render() { + let parts = this.props.controlId.split('.'); + let isCustomProperty = true; + if (parts.length === 1){ + isCustomProperty = false; + } + return ( Time - this.props.handleChange(e)} /> + this.props.handleChange(e)} + /> Time in seconds ); From dd13535e67c7fe8d822dbae7e6d19d6c85e910b3 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 15 Jul 2020 11:28:22 +0200 Subject: [PATCH 24/30] renaming Host of IC to WebSocket Endpoint for more clarity, closes #242 --- src/ic/ics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ic/ics.js b/src/ic/ics.js index e24cd93..db3b812 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -279,7 +279,7 @@ class InfrastructureComponents extends Component { {/* */} - + Date: Wed, 15 Jul 2020 12:33:51 +0200 Subject: [PATCH 25/30] Host is optional now, backend update required, closes #241 --- src/ic/new-ic.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ic/new-ic.js b/src/ic/new-ic.js index 9f0dbb1..93f1e83 100644 --- a/src/ic/new-ic.js +++ b/src/ic/new-ic.js @@ -80,10 +80,6 @@ class NewICDialog extends React.Component { uuid = false; } - if (this.state.host === '') { - host = false; - } - if (this.state.type === '') { type = false; } From ceadb074854d80c0c2e503dd67d546747be9fb14 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 15 Jul 2020 12:34:31 +0200 Subject: [PATCH 26/30] Fix an issue showing update time of IC in table, backend update required --- package-lock.json | 5 +++++ package.json | 1 + src/ic/ics.js | 11 ++++++----- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5ad0112..225cb05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8870,6 +8870,11 @@ "minimist": "^1.2.5" } }, + "moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", diff --git a/package.json b/package.json index 11aceb7..31cf318 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "jszip": "^3.5.0", "libcimsvg": "git+https://git.rwth-aachen.de/acs/public/cim/pintura-npm-package.git", "lodash": "^4.17.15", + "moment": "^2.27.0", "multiselect-react-dropdown": "^1.5.7", "node-sass": "^4.14.1", "popper.js": "^1.16.1", diff --git a/src/ic/ics.js b/src/ic/ics.js index db3b812..de97d21 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -20,6 +20,7 @@ import { Container } from 'flux/utils'; import { Button } from 'react-bootstrap'; import FileSaver from 'file-saver'; import _ from 'lodash'; +import moment from 'moment' import AppDispatcher from '../common/app-dispatcher'; import InfrastructureComponentStore from './ic-store'; @@ -256,10 +257,10 @@ class InfrastructureComponents extends Component { return style.join(' ') } - static stateUpdateModifier(updatedAt) { - const date = new Date(updatedAt); - - return date.toLocaleString('de-DE'); + stateUpdateModifier(updatedAt) { + let dateFormat = 'ddd, DD MMM YYYY HH:mm:ss'; + let dateTime = moment.utc(updatedAt, dateFormat); + return dateTime.toLocaleString('de-DE'); } render() { @@ -280,7 +281,7 @@ class InfrastructureComponents extends Component { {/* */} - + this.stateUpdateModifier(stateUpdateAt)} /> Date: Wed, 15 Jul 2020 13:33:40 +0200 Subject: [PATCH 27/30] Add UUID of IC in edit IC dialog window, closes #240 ; increase size of edit IC dialog --- src/ic/edit-ic.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ic/edit-ic.js b/src/ic/edit-ic.js index 404642c..3c3795a 100644 --- a/src/ic/edit-ic.js +++ b/src/ic/edit-ic.js @@ -85,8 +85,17 @@ class EditICDialog extends React.Component { render() { return ( - this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}> + this.onClose(c)} + onReset={() => this.resetState()} + valid={this.valid} + size='lg' + > + UUID: {this.props.ic.uuid} Name this.handleChange(e)} /> From 22da583f657d62f737f5509f6bb0cb97f9492550 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Wed, 15 Jul 2020 13:48:28 +0200 Subject: [PATCH 28/30] Make properties of IC editable #243 --- src/ic/edit-ic.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ic/edit-ic.js b/src/ic/edit-ic.js index 3c3795a..e5784e0 100644 --- a/src/ic/edit-ic.js +++ b/src/ic/edit-ic.js @@ -73,6 +73,10 @@ class EditICDialog extends React.Component { this.setState({ [e.target.id]: e.target.value }); } + handlePropertiesChange(data) { + this.setState({ properties: data }); + } + resetState() { this.setState({ name: this.props.ic.name, @@ -118,7 +122,11 @@ class EditICDialog extends React.Component { Properties - + this.handlePropertiesChange(data)} + /> From 708482ec1f03caa1d7f391d4755beb1e35525acb Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Wed, 15 Jul 2020 14:09:44 +0200 Subject: [PATCH 29/30] wip: make file (name) editable #219, edit files dialog now big enough to encompass table --- src/common/array-store.js | 5 ++ src/common/data-managers/rest-data-manager.js | 10 ++- src/file/edit-file-name.js | 79 +++++++++++++++++++ src/file/edit-files.js | 49 +++++++++--- src/scenario/scenario.js | 2 - src/styles/app.css | 21 ----- 6 files changed, 128 insertions(+), 38 deletions(-) create mode 100644 src/file/edit-file-name.js diff --git a/src/common/array-store.js b/src/common/array-store.js index 0c536f0..1c045e7 100644 --- a/src/common/array-store.js +++ b/src/common/array-store.js @@ -128,7 +128,12 @@ class ArrayStore extends ReduceStore { return super.reduce(state, action); case this.type + '/start-edit': + if(action.id){ + this.dataManager.update(action.data, action.token,action.param,action.id); + } + else{ this.dataManager.update(action.data, action.token,action.param); + } return state; case this.type + '/edited': diff --git a/src/common/data-managers/rest-data-manager.js b/src/common/data-managers/rest-data-manager.js index fb23eff..7727a4e 100644 --- a/src/common/data-managers/rest-data-manager.js +++ b/src/common/data-managers/rest-data-manager.js @@ -68,7 +68,11 @@ class RestDataManager { } } case 'remove/update': - if(param === null){ + if(id !== null){ + return this.makeURL(this.url + '/' + id); + + } + else if(param === null){ return this.makeURL(this.url + '/' + object.id); } else{ @@ -201,11 +205,11 @@ class RestDataManager { }); } - update(object, token = null, param = null) { + update(object, token = null, param = null, id = null) { var obj = {}; obj[this.type] = this.filterKeys(object); - RestAPI.put(this.requestURL('remove/update',null,param,object), obj, token).then(response => { + RestAPI.put(this.requestURL('remove/update',id,param,object), obj, token).then(response => { AppDispatcher.dispatch({ type: this.type + 's/edited', data: response[this.type] diff --git a/src/file/edit-file-name.js b/src/file/edit-file-name.js new file mode 100644 index 0000000..05481b3 --- /dev/null +++ b/src/file/edit-file-name.js @@ -0,0 +1,79 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import React from 'react'; +import {FormGroup, FormControl, FormLabel, Col} from 'react-bootstrap'; + +import Dialog from '../common/dialogs/dialog'; + +class EditFileName extends React.Component { + valid = true; + + constructor(props) { + super(props); + + this.state = { + file: {}, + + }; + } + + onClose = canceled => { + if (canceled) { + if (this.props.onClose != null) { + this.props.onClose(); + } + + return; + } + + if (this.valid && this.props.onClose != null) { + this.props.onClose(this.state.file); + } + }; + + handleChange = event => { + this.props.file.name = event.target.value; + this.setState({file: this.props.file}); + + let name = true; + + if (this.state.name === '') { + name = false; + } + + this.valid = name; + + }; + + + + render() { + return this.onClose(c)} valid={true}> +
+ + Name + + + + + +
; + } +} + +export default EditFileName; diff --git a/src/file/edit-files.js b/src/file/edit-files.js index 4f3c8a7..3e2e003 100644 --- a/src/file/edit-files.js +++ b/src/file/edit-files.js @@ -21,6 +21,7 @@ import Dialog from '../common/dialogs/dialog'; import AppDispatcher from "../common/app-dispatcher"; import Table from "../common/table"; import TableColumn from "../common/table-column"; +import EditFileName from "./edit-file-name"; class EditFilesDialog extends React.Component { @@ -32,7 +33,9 @@ class EditFilesDialog extends React.Component { this.state = { uploadFile: null, - uploadProgress: 0 + uploadProgress: 0, + editModal: false, + modalFile: {} }; } @@ -84,6 +87,22 @@ class EditFilesDialog extends React.Component { }; + closeEditModal(data){ + if(data !== {} || data !== "undefined"){ + const formData = new FormData(); + formData.append("object", data); + + AppDispatcher.dispatch({ + type: 'files/start-edit', + data: formData, + token: this.props.sessionToken, + id: data.id + }); + } + + this.setState({editModal: false}); + } + deleteFile(index){ let file = this.props.files[index] @@ -114,24 +133,24 @@ class EditFilesDialog extends React.Component { marginTop: '-40px' }; + return ( - this.onClose(c)} blendOutCancel = {true} valid={true}> + this.onClose(c)} blendOutCancel = {true} valid={true} size = 'lg'>
-
-
- - - - +
+ + + + this.deleteFile(index)} + editButton + onEdit={index => this.setState({ editModal: true, modalFile: this.props.files[index] })} />
- - +
+ + this.closeEditModal(data)} file={this.state.modalFile} /> + +
+ + ); } } diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 5b413f3..44a332f 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -420,8 +420,6 @@ class Scenario extends React.Component { } onEditFiles(){ - console.log("here r the files in scenario:"); - console.log(this.state.file); let tempFiles = []; this.state.files.forEach( file => { tempFiles.push({ diff --git a/src/styles/app.css b/src/styles/app.css index 98888f1..84d330e 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -272,27 +272,6 @@ body { supported by Chrome and Opera */ } -.edit-table table { - background-color: #fff; - table-layout: fixed; - word-wrap: break-word; - width: 467px; -} - -.edit-table th { - position: sticky; - top: 0; - text-align: left; -} - -.edit-table td{ - text-align: left; -} - -.edit-table td { - padding: 2px 8px !important; -} - /** * Toolbox */ From 57e38089b023e33f7f0f9b905fb3fe10407572da Mon Sep 17 00:00:00 2001 From: Laura Fuentes Grau Date: Wed, 15 Jul 2020 16:07:12 +0200 Subject: [PATCH 30/30] Resize dashboard buttons now work as expected if the dashboard is empty, decrease button disabled if min dashboard height has been reached #230 --- src/dashboard/dashboard.js | 10 +++++++--- src/widget/widget-toolbox.js | 18 +++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/dashboard/dashboard.js b/src/dashboard/dashboard.js index 9c3590b..584a4f2 100644 --- a/src/dashboard/dashboard.js +++ b/src/dashboard/dashboard.js @@ -73,7 +73,10 @@ class Dashboard extends Component { return thisWidgetHeight > maxHeightSoFar? thisWidgetHeight : maxHeightSoFar; }, 0); - if(dashboard.height === 0 || maxHeight + 80 > dashboard.height) + if(dashboard.height === 0){ + dashboard.height = 400; + } + else if(maxHeight + 80 > dashboard.height) { dashboard.height = maxHeight + 80; } @@ -367,11 +370,12 @@ class Dashboard extends Component { return absolutHeight > currentHeight ? absolutHeight : currentHeight; }, 0); let dashboard = this.state.dashboard; + if(value === -1){ let tempHeight = this.state.dashboard.height - 50; - if(tempHeight > (maxHeight + 80)){ + if(tempHeight >= 400 && tempHeight >= (maxHeight + 80)){ dashboard.height = tempHeight; this.setState({dashboard}); } @@ -420,7 +424,7 @@ class Dashboard extends Component {
e.preventDefault() }> {this.state.editing && - + } {!draggable?( diff --git a/src/widget/widget-toolbox.js b/src/widget/widget-toolbox.js index 5236ece..f8d6390 100644 --- a/src/widget/widget-toolbox.js +++ b/src/widget/widget-toolbox.js @@ -35,7 +35,23 @@ class WidgetToolbox extends React.Component { } }; + disableDecrease(){ + const maxHeight = Object.values(this.props.widgets).reduce((currentHeight, widget) => { + const absolutHeight = widget.y + widget.height; + + return absolutHeight > currentHeight ? absolutHeight : currentHeight; + }, 0); + + if(this.props.dashboard.height <= 400 || this.props.dashboard.height <= maxHeight + 80){ + return true; + } + + return false; + } + render() { + + const disableDecrease = this.disableDecrease(); // Only one topology widget at the time is supported const iconStyle = { color: '#007bff', @@ -82,7 +98,7 @@ class WidgetToolbox extends React.Component { Decrease dashboard height } > -