mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Merge branch 'feature_exportfunctions' into develop
This commit is contained in:
commit
ff853b4d38
13 changed files with 399 additions and 175 deletions
|
@ -99,7 +99,7 @@ class RestDataManager {
|
|||
});
|
||||
|
||||
if (this.onLoad != null) {
|
||||
this.onLoad(data);
|
||||
this.onLoad(data, token);
|
||||
}
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
|
@ -121,7 +121,7 @@ class RestDataManager {
|
|||
});
|
||||
|
||||
if (this.onLoad != null) {
|
||||
this.onLoad(data);
|
||||
this.onLoad(data, token);
|
||||
}
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
|
@ -133,16 +133,50 @@ class RestDataManager {
|
|||
}
|
||||
|
||||
|
||||
add(object, token = null, param = null) {
|
||||
add(object, token = null, param = null, subObjects = null) {
|
||||
var obj = {};
|
||||
obj[this.type] = this.filterKeys(object);
|
||||
|
||||
RestAPI.post(this.requestURL('load/add',null,param), obj, token).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/added',
|
||||
data: response[this.type],
|
||||
token: token
|
||||
});
|
||||
|
||||
// check if POST is done for import of object and issue dispatches of sub-objects
|
||||
if (subObjects !== null){
|
||||
// there are sub-objects to be added for an import
|
||||
for (let objectType of subObjects){
|
||||
let type = Object.keys(objectType) // type can be dashboards, configs, widgets, ...
|
||||
type = type[0];
|
||||
for (let newObj of objectType[type]){
|
||||
|
||||
// set the ID of the object that the sub-object shall be associated with
|
||||
if(type === "configs" || type === "dashboards"){
|
||||
// the main object is a scenario
|
||||
newObj.scenarioID = response[this.type].id
|
||||
} else if (type === "widgets") {
|
||||
// the main object is a dashboard
|
||||
newObj.dashboardID = response[this.type].id
|
||||
} else if (type === "signals") {
|
||||
// the main object is a component configuration
|
||||
newObj.configID = response[this.type].id
|
||||
}
|
||||
|
||||
// iterate over all objects of type 'type' add issue add dispatch
|
||||
AppDispatcher.dispatch({
|
||||
type: type + '/start-add',
|
||||
data: newObj,
|
||||
token: token
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: this.type + 's/add-error',
|
||||
|
|
|
@ -29,10 +29,38 @@ class ConfigStore extends ArrayStore {
|
|||
|
||||
case 'configs/loaded':
|
||||
|
||||
ConfigsDataManager.loadSignals(action.token, action.data);
|
||||
ConfigsDataManager.loadFiles(action.token, action.data);
|
||||
return super.reduce(state, action);
|
||||
|
||||
case 'configs/start-add':
|
||||
// Check if this is a recursive component config import or not
|
||||
if (action.data.hasOwnProperty("outputMapping") || action.data.hasOwnProperty("inputMapping")) {
|
||||
// import
|
||||
let subObjects = []
|
||||
let outputMapping = {}
|
||||
let inputMapping = {}
|
||||
|
||||
if (action.data.hasOwnProperty("outputMapping")){
|
||||
outputMapping["signals"] = action.data.outputMapping
|
||||
subObjects.push(outputMapping)
|
||||
delete action.data.outputMapping; // remove outputMapping signals from config object
|
||||
}
|
||||
if (action.data.hasOwnProperty("inputMapping")){
|
||||
inputMapping["signals"] = action.data.inputMapping
|
||||
subObjects.push(inputMapping)
|
||||
delete action.data.inputMapping; // remove inputMapping signals from config object
|
||||
}
|
||||
|
||||
// action.data should now contain the config and no sub-objects
|
||||
// sub-objects are treated in add method of RestDataManager
|
||||
this.dataManager.add(action.data, action.token,action.param, subObjects);
|
||||
return state
|
||||
|
||||
} else {
|
||||
// no import
|
||||
return super.reduce(state, action);
|
||||
}
|
||||
|
||||
default:
|
||||
return super.reduce(state, action);
|
||||
|
||||
|
|
|
@ -26,43 +26,35 @@ class ConfigDataManager extends RestDataManager {
|
|||
this.onLoad = this.onConfigsLoad;
|
||||
}
|
||||
|
||||
onConfigsLoad(data) {
|
||||
onConfigsLoad(data, token) {
|
||||
if (!Array.isArray(data))
|
||||
data = [ data ];
|
||||
|
||||
for (let config of data)
|
||||
this.loadICData(config);
|
||||
}
|
||||
for (let config of data) {
|
||||
|
||||
loadICData(config) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'icData/prepare',
|
||||
inputLength: parseInt(config.inputLength, 10),
|
||||
outputLength: parseInt(config.outputLength, 10),
|
||||
id: config.icID
|
||||
});
|
||||
}
|
||||
// prepare IC data
|
||||
AppDispatcher.dispatch({
|
||||
type: 'icData/prepare',
|
||||
inputLength: parseInt(config.inputLength, 10),
|
||||
outputLength: parseInt(config.outputLength, 10),
|
||||
id: config.icID
|
||||
});
|
||||
|
||||
loadSignals(token, configs){
|
||||
|
||||
for (let config of configs) {
|
||||
// request in signals
|
||||
RestAPI.get(this.makeURL('/signals?direction=in&configID=' + config.id), token).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'signals/loaded',
|
||||
data: response.signals
|
||||
});
|
||||
AppDispatcher.dispatch({
|
||||
type: 'signals/start-load',
|
||||
token: token,
|
||||
param: '?direction=in&configID=' + config.id,
|
||||
});
|
||||
|
||||
// request out signals
|
||||
RestAPI.get(this.makeURL('/signals?direction=out&configID=' + config.id), token).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'signals/loaded',
|
||||
data: response.signals
|
||||
});
|
||||
AppDispatcher.dispatch({
|
||||
type: 'signals/start-load',
|
||||
token: token,
|
||||
param: '?direction=out&configID=' + config.id,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
loadFiles(token, configs){
|
||||
|
|
|
@ -17,18 +17,19 @@
|
|||
|
||||
import React from 'react';
|
||||
import { FormGroup, FormControl, FormLabel } from 'react-bootstrap';
|
||||
import _ from 'lodash';
|
||||
|
||||
import Dialog from '../common/dialogs/dialog';
|
||||
|
||||
class ImportConfigDialog extends React.Component {
|
||||
imported = false;
|
||||
valid = false;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
config: {}
|
||||
config: {},
|
||||
name: '',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -39,12 +40,13 @@ class ImportConfigDialog extends React.Component {
|
|||
return;
|
||||
}
|
||||
|
||||
this.props.onClose(this.state.config);
|
||||
this.props.onClose(this.state);
|
||||
}
|
||||
|
||||
resetState = () => {
|
||||
this.setState({
|
||||
config: {}
|
||||
config: {},
|
||||
name: ''
|
||||
});
|
||||
|
||||
this.imported = false;
|
||||
|
@ -58,46 +60,65 @@ class ImportConfigDialog extends React.Component {
|
|||
}
|
||||
|
||||
// create file reader
|
||||
const reader = new FileReader();
|
||||
const self = this;
|
||||
let reader = new FileReader();
|
||||
let self = this;
|
||||
|
||||
reader.onload = event => {
|
||||
const config = JSON.parse(event.target.result);
|
||||
|
||||
config.icID = this.props.ics.length > 0 ? this.props.ics[0]._id : null;
|
||||
|
||||
self.imported = true;
|
||||
|
||||
this.setState({ config: config });
|
||||
self.valid = true;
|
||||
this.setState({name: config.name, config: config });
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
handleICChange = event => {
|
||||
const config = this.state.config;
|
||||
handleChange(e, index) {
|
||||
this.setState({ [e.target.id]: e.target.value });
|
||||
}
|
||||
|
||||
config.icID = event.target.value;
|
||||
validateForm(target) {
|
||||
// check all controls
|
||||
let name = true;
|
||||
|
||||
this.setState({ config: config });
|
||||
if (this.state.name === '') {
|
||||
name = false;
|
||||
}
|
||||
this.valid = name;
|
||||
|
||||
// return state to control
|
||||
if (target === 'name'){
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Dialog show={this.props.show} title="Import Component Configuration" buttonTitle="Import" onClose={(c) => this.onClose(c)} onReset={this.resetState} valid={this.imported}>
|
||||
<Dialog
|
||||
show={this.props.show}
|
||||
title="Import Component Configuration"
|
||||
buttonTitle="Import"
|
||||
onClose={(c) => this.onClose(c)}
|
||||
onReset={() => this.resetState()}
|
||||
valid={this.valid} >
|
||||
<form>
|
||||
<FormGroup controlId='file'>
|
||||
<FormLabel>Component Configuration File</FormLabel>
|
||||
<FormControl type='file' onChange={this.loadFile} />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup controlId='IC'>
|
||||
<FormLabel>Infrastructure Component</FormLabel>
|
||||
<FormControl disabled={this.imported === false} as='select' placeholder='Select infrastructure component' value={this.state.config.icID} onChange={this.handleICChange}>
|
||||
{this.props.ics.map(ic => (
|
||||
<option key={ic.id} value={ic.id}>{_.get(ic, 'properties.name') || _.get(ic, 'rawProperties.name')}</option>
|
||||
))}
|
||||
</FormControl>
|
||||
<FormGroup controlId="name" >
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl
|
||||
readOnly={!this.imported}
|
||||
isValid={this.validateForm('name')}
|
||||
type="text"
|
||||
placeholder="Enter name"
|
||||
value={this.state.name}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
/>
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
</form>
|
||||
</Dialog>
|
||||
|
|
|
@ -18,4 +18,40 @@
|
|||
import ArrayStore from '../common/array-store';
|
||||
import DashboardsDataManager from './dashboards-data-manager';
|
||||
|
||||
export default new ArrayStore('dashboards', DashboardsDataManager);
|
||||
class DashboardStore extends ArrayStore {
|
||||
constructor() {
|
||||
super('dashboards', DashboardsDataManager);
|
||||
}
|
||||
|
||||
reduce(state, action) {
|
||||
|
||||
switch (action.type) {
|
||||
case 'dashboards/start-add':
|
||||
|
||||
// Check if this is a recursive dashboard import or not
|
||||
if (action.data.hasOwnProperty("widgets")) {
|
||||
// import
|
||||
let subObjects = []
|
||||
let widgets = {}
|
||||
widgets["widgets"] = action.data.widgets
|
||||
subObjects.push(widgets)
|
||||
delete action.data.widgets; // remove widgets from dashboard object
|
||||
|
||||
// action.data should now contain the dashboard and no sub-objects
|
||||
// sub-objects are treated in add method of RestDataManager
|
||||
this.dataManager.add(action.data, action.token,action.param, subObjects);
|
||||
return state
|
||||
|
||||
} else {
|
||||
// no import
|
||||
return super.reduce(state, action);
|
||||
}
|
||||
|
||||
default:
|
||||
return super.reduce(state, action);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new DashboardStore();
|
||||
|
|
|
@ -16,5 +16,29 @@
|
|||
******************************************************************************/
|
||||
|
||||
import RestDataManager from '../common/data-managers/rest-data-manager';
|
||||
import AppDispatcher from "../common/app-dispatcher";
|
||||
|
||||
export default new RestDataManager('dashboard', '/dashboards');
|
||||
class DashboardsDataManager extends RestDataManager{
|
||||
constructor() {
|
||||
super('dashboard', '/dashboards');
|
||||
this.onLoad = this.onDashboardsLoad
|
||||
}
|
||||
|
||||
onDashboardsLoad(data, token){
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
data = [data];
|
||||
}
|
||||
|
||||
for (let dashboard of data){
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-load',
|
||||
token: token,
|
||||
param: '?dashboardID=' + dashboard.id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default new DashboardsDataManager();
|
||||
|
|
|
@ -67,27 +67,6 @@ class ImportDashboardDialog extends React.Component {
|
|||
// read IC
|
||||
const dashboard = JSON.parse(event.target.result);
|
||||
|
||||
/*let defaultIC = "";
|
||||
if (self.props.configs != null) {
|
||||
defaultIC = self.props.configs[0].icID;
|
||||
}
|
||||
|
||||
dashboard.widgets.forEach(widget => {
|
||||
switch (widget.type) {
|
||||
case 'Value':
|
||||
case 'Plot':
|
||||
case 'Table':
|
||||
case 'PlotTable':
|
||||
case 'Gauge':
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
self.imported = true;
|
||||
self.valid = true;
|
||||
self.setState({ name: dashboard.name, widgets: dashboard.widgets, grid: dashboard.grid });
|
||||
|
@ -107,21 +86,36 @@ class ImportDashboardDialog extends React.Component {
|
|||
this.valid = name;
|
||||
|
||||
// return state to control
|
||||
if (target === 'name') return name ? "success" : "error";
|
||||
if (target === 'name'){
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Dialog show={this.props.show} title="Import Dashboard" buttonTitle="Import" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
|
||||
<Dialog
|
||||
show={this.props.show}
|
||||
title="Import Dashboard"
|
||||
buttonTitle="Import"
|
||||
onClose={(c) => this.onClose(c)}
|
||||
onReset={() => this.resetState()}
|
||||
valid={this.valid}>
|
||||
<form>
|
||||
<FormGroup controlId="file">
|
||||
<FormLabel>Dashboard File</FormLabel>
|
||||
<FormControl type="file" onChange={(e) => this.loadFile(e.target.files)} />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup controlId="name" validationState={this.validateForm('name')}>
|
||||
<FormGroup controlId="name" >
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl readOnly={!this.imported} type="text" placeholder="Enter name" value={this.state.name} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl
|
||||
readOnly={!this.imported}
|
||||
isValid={this.validateForm('name')}
|
||||
type="text"
|
||||
placeholder="Enter name"
|
||||
value={this.state.name}
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
/>
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
</form>
|
||||
|
|
|
@ -32,6 +32,7 @@ class ImportScenarioDialog extends React.Component {
|
|||
name: '',
|
||||
running: '',
|
||||
configs: [],
|
||||
dashboards: [],
|
||||
startParameters: {}
|
||||
};
|
||||
}
|
||||
|
@ -51,15 +52,6 @@ class ImportScenarioDialog extends React.Component {
|
|||
}
|
||||
|
||||
handleChange(e, index) {
|
||||
/*if (e.target.id === 'icID') {
|
||||
const configs = this.state.configs;
|
||||
configs[index].icID = JSON.parse(e.target.value);
|
||||
|
||||
this.setState({ configs: configs });
|
||||
|
||||
return;
|
||||
}*/
|
||||
|
||||
this.setState({ [e.target.id]: e.target.value });
|
||||
|
||||
// check all controls
|
||||
|
@ -94,7 +86,7 @@ class ImportScenarioDialog extends React.Component {
|
|||
|
||||
self.imported = true;
|
||||
self.valid = true;
|
||||
self.setState({ name: scenario.name, configs: scenario.configs, startParameters: scenario.startParameters, running: scenario.running });
|
||||
self.setState({ name: scenario.name, configs: scenario.configs, dashboards: scenario.dashboards, startParameters: scenario.startParameters, running: scenario.running });
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
|
|
|
@ -19,4 +19,50 @@
|
|||
import ScenariosDataManager from './scenarios-data-manager';
|
||||
import ArrayStore from '../common/array-store';
|
||||
|
||||
export default new ArrayStore('scenarios', ScenariosDataManager);
|
||||
class ScenarioStore extends ArrayStore{
|
||||
constructor() {
|
||||
super('scenarios', ScenariosDataManager);
|
||||
}
|
||||
|
||||
reduce(state, action) {
|
||||
switch (action.type) {
|
||||
|
||||
case 'scenarios/start-add':
|
||||
|
||||
// Check if this is a recursive scenario import or not
|
||||
if (action.data.hasOwnProperty("configs") || action.data.hasOwnProperty("dashboards")) {
|
||||
// import
|
||||
let subObjects = []
|
||||
let configs = {}
|
||||
let dashboards = {}
|
||||
|
||||
if (action.data.hasOwnProperty("configs")){
|
||||
configs["configs"] = action.data.configs
|
||||
subObjects.push(configs)
|
||||
delete action.data.configs; // remove configs from scenario object
|
||||
}
|
||||
if (action.data.hasOwnProperty("dashboards")){
|
||||
dashboards["dashboards"] = action.data.dashboards
|
||||
subObjects.push(dashboards)
|
||||
delete action.data.dashboards; // remove dashboards from scenario object
|
||||
}
|
||||
|
||||
// action.data should now contain the scenario and no sub-objects
|
||||
// sub-objects are treated in add method of RestDataManager
|
||||
this.dataManager.add(action.data, action.token,action.param, subObjects);
|
||||
return state
|
||||
|
||||
} else {
|
||||
// no import
|
||||
return super.reduce(state, action);
|
||||
}
|
||||
|
||||
default:
|
||||
return super.reduce(state, action);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default new ScenarioStore();
|
||||
|
|
|
@ -40,10 +40,12 @@ import DeleteDialog from '../common/dialogs/delete-dialog';
|
|||
import EditConfigDialog from "../componentconfig/edit-config";
|
||||
import EditSignalMapping from "../signal/edit-signal-mapping";
|
||||
import FileStore from "../file/file-store"
|
||||
import WidgetStore from "../widget/widget-store";
|
||||
|
||||
class Scenario extends React.Component {
|
||||
|
||||
static getStores() {
|
||||
return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore];
|
||||
return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
@ -96,7 +98,6 @@ class Scenario extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
//load selected scenario
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-load',
|
||||
|
@ -104,29 +105,14 @@ class Scenario extends React.Component {
|
|||
token: this.state.sessionToken
|
||||
});
|
||||
|
||||
// load component configurations for selected scenario
|
||||
AppDispatcher.dispatch({
|
||||
type: 'configs/start-load',
|
||||
token: this.state.sessionToken,
|
||||
param: '?scenarioID='+this.state.scenario.id,
|
||||
});
|
||||
|
||||
// load dashboards of selected scenario
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-load',
|
||||
token: this.state.sessionToken,
|
||||
param: '?scenarioID='+this.state.scenario.id,
|
||||
});
|
||||
|
||||
// load ICs to enable that component configs and dashboards work with them
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/start-load',
|
||||
token: this.state.sessionToken,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ##############################################
|
||||
* Component Configuration modification methods
|
||||
############################################## */
|
||||
|
@ -180,33 +166,47 @@ class Scenario extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
importConfig(config){
|
||||
importConfig(data){
|
||||
this.setState({ importConfigModal: false });
|
||||
|
||||
if (config == null) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
config.scenario = this.state.scenario.id;
|
||||
let newConfig = JSON.parse(JSON.stringify(data.config))
|
||||
|
||||
newConfig["scenarioID"] = this.state.scenario.id;
|
||||
newConfig.name = data.name;
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'configs/start-add',
|
||||
data: config,
|
||||
data: newConfig,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
|
||||
this.setState({ scenario: {} }, () => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-load',
|
||||
data: this.props.match.params.scenario,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exportConfig(index) {
|
||||
// filter properties
|
||||
const config = Object.assign({}, this.state.configs[index]);
|
||||
let config = JSON.parse(JSON.stringify(this.state.configs[index]));
|
||||
|
||||
let signals = JSON.parse(JSON.stringify(SignalStore.getState().filter(s => s.configID === parseInt(config.id, 10))));
|
||||
signals.forEach((signal) => {
|
||||
delete signal.configID;
|
||||
delete signal.id;
|
||||
})
|
||||
|
||||
// two separate lists for inputMapping and outputMapping
|
||||
let inputSignals = signals.filter(s => s.direction === 'in');
|
||||
let outputSignals = signals.filter(s => s.direction === 'out');
|
||||
|
||||
// add signal mappings to config
|
||||
config["inputMapping"] = inputSignals;
|
||||
config["outputMapping"] = outputSignals;
|
||||
|
||||
delete config.id;
|
||||
delete config.scenarioID;
|
||||
delete config.inputLength;
|
||||
delete config.outputLength;
|
||||
|
||||
// show save dialog
|
||||
const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
|
||||
|
@ -311,9 +311,12 @@ class Scenario extends React.Component {
|
|||
this.setState({ importDashboardModal: false });
|
||||
|
||||
if (data) {
|
||||
let newDashboard = JSON.parse(JSON.stringify(data));
|
||||
newDashboard["scenarioID"] = this.state.scenario.id;
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-add',
|
||||
data,
|
||||
data: newDashboard,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
|
@ -321,9 +324,16 @@ class Scenario extends React.Component {
|
|||
|
||||
exportDashboard(index) {
|
||||
// filter properties
|
||||
const dashboard = Object.assign({}, this.state.dashboards[index]);
|
||||
let dashboard = JSON.parse(JSON.stringify(this.state.dashboards[index]));
|
||||
|
||||
// TODO get elements recursively
|
||||
let widgets = JSON.parse(JSON.stringify(WidgetStore.getState().filter(w => w.dashboardID === parseInt(dashboard.id, 10))));
|
||||
widgets.forEach((widget) => {
|
||||
delete widget.dashboardID;
|
||||
delete widget.id;
|
||||
})
|
||||
dashboard["widgets"] = widgets;
|
||||
delete dashboard.scenarioID;
|
||||
delete dashboard.id;
|
||||
|
||||
// show save dialog
|
||||
const blob = new Blob([JSON.stringify(dashboard, null, 2)], { type: 'application/json' });
|
||||
|
|
|
@ -16,41 +16,36 @@
|
|||
******************************************************************************/
|
||||
|
||||
import RestDataManager from '../common/data-managers/rest-data-manager';
|
||||
import RestAPI from "../common/api/rest-api";
|
||||
import AppDispatcher from "../common/app-dispatcher";
|
||||
|
||||
class ScenariosDataManager extends RestDataManager {
|
||||
constructor() {
|
||||
super('scenario', '/scenarios');
|
||||
|
||||
this.onLoad = this.onScenariosLoad
|
||||
}
|
||||
|
||||
getComponentConfigs(token, id) {
|
||||
RestAPI.get(this.makeURL('/scenarios/' + id + '/configs'), token).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/configs',
|
||||
configs: response.configs
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/configs-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
onScenariosLoad(data, token){
|
||||
|
||||
getDashboards(token, id) {
|
||||
RestAPI.get(this.makeURL('/scenarios/' + id + '/dashboards'), token).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/dashboards',
|
||||
dashboards: response.dashboards
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/dashboards-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!Array.isArray(data)) {
|
||||
data = [data];
|
||||
}
|
||||
|
||||
for (let scenario of data){
|
||||
AppDispatcher.dispatch({
|
||||
type: 'configs/start-load',
|
||||
token: token,
|
||||
param: '?scenarioID=' + scenario.id
|
||||
});
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-load',
|
||||
token: token,
|
||||
param: '?scenarioID=' + scenario.id
|
||||
});
|
||||
|
||||
// TODO add dispatch for files
|
||||
}
|
||||
}
|
||||
}
|
||||
export default new ScenariosDataManager();
|
||||
|
|
|
@ -23,6 +23,10 @@ import FileSaver from 'file-saver';
|
|||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import ScenarioStore from './scenario-store';
|
||||
import LoginStore from '../user/login-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 Table from '../common/table';
|
||||
|
@ -33,18 +37,20 @@ import ImportScenarioDialog from './import-scenario';
|
|||
|
||||
import DeleteDialog from '../common/dialogs/delete-dialog';
|
||||
|
||||
|
||||
class Scenarios extends Component {
|
||||
|
||||
static getStores() {
|
||||
return [ ScenarioStore, LoginStore ];
|
||||
return [ScenarioStore, LoginStore, DashboardStore, WidgetStore, ConfigStore, SignalStore];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
const scenarios = ScenarioStore.getState();
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
|
||||
return {
|
||||
scenarios,
|
||||
sessionToken,
|
||||
scenarios: ScenarioStore.getState(),
|
||||
dashboards: DashboardStore.getState(),
|
||||
configs: ConfigStore.getState(),
|
||||
sessionToken: LoginStore.getState().token,
|
||||
|
||||
newModal: false,
|
||||
deleteModal: false,
|
||||
|
@ -63,23 +69,20 @@ class Scenarios extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
componentDidUpdate() {}
|
||||
|
||||
closeNewModal(data) {
|
||||
this.setState({ newModal : false });
|
||||
|
||||
if (data) {
|
||||
if(data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-add',
|
||||
data,
|
||||
token: this.state.sessionToken
|
||||
data: data,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
this.setState({ newModal: false });
|
||||
}
|
||||
|
||||
showDeleteModal(id) {
|
||||
// get scenario by id
|
||||
var deleteScenario;
|
||||
let deleteScenario;
|
||||
|
||||
this.state.scenarios.forEach((scenario) => {
|
||||
if (scenario.id === id) {
|
||||
|
@ -97,6 +100,16 @@ class Scenarios extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
this.state.dashboards.forEach((dashboard) => {
|
||||
if (dashboard.id === this.state.modalScenario.id) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-remove',
|
||||
data: dashboard,
|
||||
token: this.state.sessionToken
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-remove',
|
||||
data: this.state.modalScenario,
|
||||
|
@ -118,7 +131,7 @@ class Scenarios extends Component {
|
|||
}
|
||||
|
||||
closeEditModal(data) {
|
||||
this.setState({ editModal : false });
|
||||
this.setState({ editModal: false });
|
||||
|
||||
if (data != null) {
|
||||
AppDispatcher.dispatch({
|
||||
|
@ -135,8 +148,8 @@ class Scenarios extends Component {
|
|||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-add',
|
||||
data,
|
||||
token: this.state.sessionToken
|
||||
data: data,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -150,14 +163,54 @@ class Scenarios extends Component {
|
|||
};
|
||||
|
||||
exportScenario(index) {
|
||||
// filter properties
|
||||
let scenario = Object.assign({}, this.state.scenarios[index]);
|
||||
// copy by value by converting to JSON and back
|
||||
// otherwise, IDs of state objects will be deleted
|
||||
let scenario = JSON.parse(JSON.stringify(this.state.scenarios[index]));
|
||||
let configs = JSON.parse(JSON.stringify(this.state.configs.filter(config => config.scenarioID === scenario.id)));
|
||||
let dashboards = JSON.parse(JSON.stringify(this.state.dashboards.filter(dashb => dashb.scenarioID === scenario.id)));
|
||||
|
||||
// create JSON object and add component configs
|
||||
delete scenario.id;
|
||||
let jsonObj = scenario;
|
||||
|
||||
// TODO request missing scenario parameters (Dashboards and component configs) recursively for export
|
||||
configs.forEach((config) => {
|
||||
let signals = JSON.parse(JSON.stringify(SignalStore.getState().filter(s => s.configID === parseInt(config.id, 10))));
|
||||
signals.forEach((signal) => {
|
||||
delete signal.configID;
|
||||
delete signal.id;
|
||||
})
|
||||
|
||||
// show save dialog
|
||||
const blob = new Blob([JSON.stringify(scenario, null, 2)], { type: 'application/json' });
|
||||
// two separate lists for inputMapping and outputMapping
|
||||
let inputSignals = signals.filter(s => s.direction === 'in');
|
||||
let outputSignals = signals.filter(s => s.direction === 'out');
|
||||
|
||||
// add signal mappings to config
|
||||
config["inputMapping"] = inputSignals;
|
||||
config["outputMapping"] = outputSignals;
|
||||
|
||||
delete config.id;
|
||||
delete config.scenarioID;
|
||||
delete config.inputLength;
|
||||
delete config.outputLength;
|
||||
})
|
||||
jsonObj["configs"] = configs;
|
||||
|
||||
// add Dashboards and Widgets to JSON object
|
||||
dashboards.forEach((dboard) => {
|
||||
let widgets = JSON.parse(JSON.stringify(WidgetStore.getState().filter(w => w.dashboardID === parseInt(dboard.id, 10))));
|
||||
widgets.forEach((widget) => {
|
||||
delete widget.dashboardID;
|
||||
delete widget.id;
|
||||
})
|
||||
dboard["widgets"] = widgets;
|
||||
delete dboard.scenarioID;
|
||||
delete dboard.id;
|
||||
});
|
||||
jsonObj["dashboards"] = dashboards;
|
||||
|
||||
|
||||
// create JSON string and show save dialog
|
||||
const blob = new Blob([JSON.stringify(jsonObj, null, 2)], { type: 'application/json' });
|
||||
FileSaver.saveAs(blob, 'scenario - ' + scenario.name + '.json');
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ class SignalsDataManager extends RestDataManager{
|
|||
|
||||
reloadConfig(token, data){
|
||||
// request in signals
|
||||
console.log("Reloading component config due to signal add/remove")
|
||||
RestAPI.get(this.makeURL('/configs/' + data.configID), token).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'configs/edited',
|
||||
|
|
Loading…
Add table
Reference in a new issue