1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

Merge branch 'add-scenario-frame' into example-dashboard

# Conflicts:
#	src/dashboard/dashboard.js
This commit is contained in:
Sonja Happ 2019-11-26 16:39:05 +01:00
commit 7fc0ed2d5c
11 changed files with 189 additions and 189 deletions

View file

@ -51,7 +51,6 @@ import Scenario from './scenario/scenario';
import SimulationModel from './simulationmodel/simulation-model';
import Users from './user/users';
import User from './user/user';
import ExDashboard from './dashboard/exdashboard';
import './styles/app.css';
@ -146,7 +145,6 @@ class App extends React.Component {
<div className={`app-content app-content-margin-left`}>
<Route exact path="/" component={Home} />
<Route path="/home" component={Home} />
<Route path="/exdashboard/:dashboard" component={Dashboard} />
<Route path="/dashboards/:dashboard" component={Dashboard} />
<Route exact path="/scenarios" component={Scenarios} />
<Route path="/scenarios/:scenario" component={Scenario} />
@ -154,7 +152,6 @@ class App extends React.Component {
<Route path="/simulators" component={Simulators} />
<Route path="/user" component={User} />
<Route path="/users" component={Users} />
<Route path="/exdashboard" component={ExDashboard} />
</div>
</div>

View file

@ -37,7 +37,7 @@ const REQUEST_TIMEOUT_NOTIFICATION = {
level: 'error'
};
// Check if the error was due to network failure, timeouts, etc.
// Check if the error was due to network failure, timeouts, etc.
// Can be used for the rest of requests
function isNetworkError(err) {
let result = false;
@ -45,7 +45,7 @@ function isNetworkError(err) {
// If not status nor response fields, it is a network error. TODO: Handle timeouts
if (err.status == null || err.response == null) {
result = true;
let notification = err.timeout? REQUEST_TIMEOUT_NOTIFICATION : SERVER_NOT_REACHABLE_NOTIFICATION;
NotificationsDataManager.addNotification(notification);
}
@ -54,7 +54,6 @@ function isNetworkError(err) {
class RestAPI {
get(url, token) {
console.log(url);
return new Promise(function (resolve, reject) {
var req = request.get(url);
@ -74,14 +73,13 @@ class RestAPI {
}
post(url, body, token) {
console.log(url);
return new Promise(function (resolve, reject) {
var req = request.post(url).send(body).timeout({ response: 5000 }); // Simple response start timeout (3s)
if (token != null) {
req.set('Authorization', "Bearer " + token);
}
req.end(function (error, res) {
if (res == null || res.status !== 200) {

View file

@ -79,30 +79,30 @@ class ArrayStore extends ReduceStore {
case this.type + '/loaded':
if (Array.isArray(action.data)) {
console.log(" loaded Array: ");
console.log(action.data);
console.log(state);
console.log("####### loaded array of type " + this.type);
//console.log(action.data);
//console.log(state);
return this.updateElements(state, action.data);
} else {
console.log("loaded single object: ");
console.log([action.data]);
console.log(state);
console.log("####### loaded single object of type " + this.type);
//console.log([action.data]);
//console.log(state);
return this.updateElements(state, [action.data]);
}
case this.type + '/load-error':
if (action.error && !action.error.handled && action.error.response) {
const USER_LOAD_ERROR_NOTIFICATION = {
title: 'Failed to load',
message: action.error.response.body.message,
level: 'error'
};
NotificationsDataManager.addNotification(USER_LOAD_ERROR_NOTIFICATION);
}
return super.reduce(state, action);
case this.type + '/start-add':
this.dataManager.add(action.data, action.token,action.param);
return state;
@ -111,7 +111,7 @@ class ArrayStore extends ReduceStore {
return this.updateElements(state, [action.data]);
case this.type + '/add-error':
return state;
@ -133,10 +133,10 @@ class ArrayStore extends ReduceStore {
level: 'error'
};
NotificationsDataManager.addNotification(USER_REMOVE_ERROR_NOTIFICATION);
}
return super.reduce(state, action);
case this.type + '/start-edit':
this.dataManager.update(action.data, action.token,action.param);
return state;

View file

@ -57,7 +57,6 @@ class RestDataManager {
case 'load/add':
if (param === null){
if(id != null){
console.log("id != 0");
return this.makeURL(this.url + '/' + id);
}
else {
@ -66,10 +65,10 @@ class RestDataManager {
}
else{
if(id != null){
return this.makeURL(this.url + '/' + id + '?' + param);
return this.makeURL(this.url + '/' + id + param);
}
else {
return this.makeURL(this.url + '?' + param)
return this.makeURL(this.url + param)
}
}
case 'remove/update':
@ -77,7 +76,7 @@ class RestDataManager {
return this.makeURL(this.url + '/' + object.id);
}
else{
return this.makeURL(this.url + '/' + object.id + '?' + param);
return this.makeURL(this.url + '/' + object.id + param);
}
default:
console.log("something went wrong");
@ -87,11 +86,10 @@ class RestDataManager {
load(id, token = null,param = null) {
if (id != null) {
console.log("rdm load was called");
// load single object
RestAPI.get(this.requestURL('load/add',id,param), token).then(response => {
const data = this.filterKeys(response[this.type]);
AppDispatcher.dispatch({
type: this.type + 's/loaded',
data: data
@ -129,7 +127,7 @@ class RestDataManager {
});
}
}
add(object, token = null, param = null) {
var obj = {};
@ -162,7 +160,7 @@ class RestDataManager {
});
});
}
update(object, token = null, param = null) {
var obj = {};
obj[this.type] = this.filterKeys(object);
@ -179,8 +177,8 @@ class RestDataManager {
});
});
}
};

View file

@ -35,7 +35,6 @@ class SidebarMenu extends React.Component {
<li><NavLink to="/home" activeClassName="active" title="Home">Home</NavLink></li>
<li><NavLink to="/scenarios" activeClassName="active" title="Scenarios">Scenarios</NavLink></li>
<li><NavLink to="/simulators" activeClassName="active" title="Simulators">Simulators</NavLink></li>
<li><NavLink to="/exdashboard" activeClassName="active" title="Example Dashboard">Example Dashboard</NavLink></li>
{ this.props.currentRole === 'Admin' ?
<li><NavLink to="/users" activeClassName="active" title="User Management">User Management</NavLink></li> : ''
}

View file

@ -61,24 +61,24 @@ class Dashboard extends React.Component {
console.log("dashboard calculate state was called: " + props.match.params.dashboard);
let dashboards = DashboardStore.getState()
let rawDashboard = dashboards[props.match.params.dashboard - 1];
let str = JSON.stringify(rawDashboard, null, 4);
console.log(str);
if (rawDashboard != null) {
dashboard = Map(rawDashboard);
console.log("dashboard: " + dashboard);
// convert widgets list to a dictionary to be able to reference widgets
// convert widgets list to a dictionary to be able to reference widgets
//let widgets = {};
let rawWidgets = WidgetStore.getState();
if(rawWidgets.length === 0){
AppDispatcher.dispatch({
type: 'widgets/start-load',
token: sessionToken,
param: 'dashboardID=1'
param: '?dashboardID=1'
});
}
@ -92,14 +92,14 @@ class Dashboard extends React.Component {
});
}
console.log("here are the widgets: ");
console.log(rawWidgets);
dashboard = dashboard.set('widgets', rawWidgets);
console.log("")
/* for(let widget of dashboard.get('widgets')){
console.log("load files got called")
console.log(widget);
@ -110,9 +110,9 @@ class Dashboard extends React.Component {
});
}
*/
//ist das überhaupt nötiG??
/* if (this.state.dashboard.has('id') === false) {
AppDispatcher.dispatch({
@ -122,14 +122,14 @@ class Dashboard extends React.Component {
});
}
*/
/*if(Object.keys(widgets).length !== 0 ){
this.computeHeightWithWidgets(widgets);
}
let selectedDashboards = dashboard;
let selectedDashboards = dashboard;
/* this.setState({ dashboard: selectedDashboards, project: null });
@ -151,10 +151,10 @@ class Dashboard extends React.Component {
console.log("!! the widget key: "+ widgetKey);
let thisWidget = widgets[widgetKey];
let thisWidgetHeight = thisWidget.y + thisWidget.height;
return thisWidgetHeight > maxHeightSoFar? thisWidgetHeight : maxHeightSoFar;
}, 0);
console.log("now the object keys: ");
console.log(Object.keys(widgets));
let simulationModels = [];
@ -208,7 +208,7 @@ class Dashboard extends React.Component {
}
}
componentWillUnmount() {
//document.removeEventListener('keydown', this.handleKeydown.bind(this));
@ -261,7 +261,7 @@ class Dashboard extends React.Component {
default:
}
}
}
/*
* Adapt the area's height with the position of the new widget.
@ -494,7 +494,7 @@ class Dashboard extends React.Component {
<WidgetContextMenu key={widgetKey} index={parseInt(widgetKey,10)} widget={widgets[widgetKey]} onEdit={this.editWidget} onDelete={this.deleteWidget} onChange={this.widgetChange} />
))}
</div>
</div>;
}
@ -503,4 +503,4 @@ class Dashboard extends React.Component {
let fluxContainerConverter = require('../common/FluxContainerConverter');
export default Fullscreenable()(Container.create(fluxContainerConverter.convert(Dashboard), { withProps: true }));
//<EditWidget sessionToken={this.state.sessionToken} show={this.state.editModal} onClose={this.closeEdit} widget={this.state.modalData} simulationModels={this.state.simulationModels} files={this.state.files} />
//onEdit={this.startEditing}
//onEdit={this.startEditing}

View file

@ -1,85 +0,0 @@
import React, { Component } from 'react';
import { Container } from 'flux/utils';
import DashboardStore from './dashboard-store';
import AppDispatcher from '../common/app-dispatcher';
import Table from '../common/table';
import TableColumn from '../common/table-column';
import UserStore from '../user/user-store';
import { Button } from 'react-bootstrap';
import Icon from '../common/icon';
class ExDashboard extends Component {
static getStores() {
return [ DashboardStore ];
}
static calculateState(prevState, props) {
prevState = prevState || {};
console.log("calculateState has been called");
const dashboards = DashboardStore.getState();
let tokenState = UserStore.getState().token;
console.log(dashboards);
return{
dashboards,
tokenState
}
}
componentDidMount() {
AppDispatcher.dispatch({
type: 'dashboards/start-load',
token: this.state.tokenState,
param: 'scenarioID=1'
});
}
loadDash(){
console.log('bis hierhin gekommen');
AppDispatcher.dispatch({
type: 'dashboards/start-load',
token: this.state.tokenState,
param: 'scenarioID=1'
});
}
render() {
const buttonStyle = {
marginLeft: '10px'
};
return (
<div className='section'>
<h1>Dashboards</h1>
<Table data={this.state.dashboards}>
<TableColumn title='Name' dataKey='name' link='/exdashboard/' linkKey='id' />
<TableColumn title='Grid' dataKey='grid' link='/edashboard/' linkKey='id' />
<TableColumn title='ScenarioID' dataKey='scenarioID' link='/exdashboard/' linkKey='id' />
</Table>
<div style={{ float: 'right' }}>
<Button onClick={() => this.loadDash} style={buttonStyle}><Icon icon="plus" /> Add</Button>
</div>
</div>
);
}
}
let fluxContainerConverter = require('../common/FluxContainerConverter');
export default Container.create(fluxContainerConverter.convert(ExDashboard));

View file

@ -24,7 +24,7 @@ import { FormGroup, FormControl, FormLabel } from 'react-bootstrap';
import Dialog from '../common/dialogs/dialog';
class NewVisualzationDialog extends React.Component {
class NewDashboardDialog extends React.Component {
valid: false;
constructor(props) {
@ -84,4 +84,4 @@ class NewVisualzationDialog extends React.Component {
}
}
export default NewVisualzationDialog;
export default NewDashboardDialog;

View file

@ -27,6 +27,7 @@ import _ from 'lodash';
import ScenarioStore from './scenario-store';
import SimulatorStore from '../simulator/simulator-store';
import DashboardStore from '../dashboard/dashboard-store';
import SimulationModelStore from '../simulationmodel/simulation-model-store';
import UserStore from '../user/user-store';
import AppDispatcher from '../common/app-dispatcher';
@ -35,75 +36,83 @@ import Icon from '../common/icon';
import Table from '../common/table';
import TableColumn from '../common/table-column';
import ImportSimulationModelDialog from '../simulationmodel/import-simulation-model';
import ImportDashboardDialog from "../dashboard/import-dashboard";
import NewDashboardDialog from "../dashboard/new-dashboard";
import SimulatorAction from '../simulator/simulator-action';
import DeleteDialog from '../common/dialogs/delete-dialog';
class Scenario extends React.Component {
static getStores() {
return [ ScenarioStore, SimulatorStore, SimulationModelStore, UserStore ];
return [ ScenarioStore, SimulationModelStore, DashboardStore, SimulatorStore];
}
static calculateState(prevState, props) {
// get selected scenario
const sessionToken = UserStore.getState().token;
let scenario = ScenarioStore.getState().find(s => s.id === props.match.params.scenario);
const scenario = ScenarioStore.getState().find(s => s.id === parseInt(props.match.params.scenario, 10));
if (scenario == null) {
AppDispatcher.dispatch({
type: 'scenarios/start-load',
data: props.match.params.scenario,
token: sessionToken
});
scenario = {};
console.log(scenario);
}
// load models
let simulationModels = [];
if (scenario.simulationModels != null) {
simulationModels = SimulationModelStore.getState().filter(m => m != null && scenario.simulationModels.includes(m.id));
}
// obtain all dashboards of a scenario
let dashboards = DashboardStore.getState().filter(dashb => dashb.scenarioID === parseInt(props.match.params.scenario, 10));
// obtain all simulation models of a scenario
let simulationmodels = SimulationModelStore.getState().filter(simmodel => simmodel.scenarioID === parseInt(props.match.params.scenario, 10));
return {
simulationModels,
scenario,
//simulators: SimulatorStore.getState(),
sessionToken,
simulationModels: simulationmodels,
dashboards: dashboards,
simulators: SimulatorStore.getState(),
deleteModal: false,
importModal: false,
modalData: {},
deleteSimulationModelModal: false,
importSimulationModelModal: false,
modalSimulationModelData: {},
selectedSimulationModels: [],
selectedSimulationModels: []
newDashboardModal: false,
deleteDashboardModal: false,
importDashboardModal: false,
modalDashboardData: {},
}
}
componentWillMount() {
//load selected scenario
AppDispatcher.dispatch({
type: 'scenarios/start-load',
data: this.state.scenario.id,
token: this.state.sessionToken
});
// load simulation models for selected scenario
AppDispatcher.dispatch({
type: 'simulationModels/start-load',
token: this.state.sessionToken
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 simulators to enable that simulation models work with them
AppDispatcher.dispatch({
type: 'simulators/start-load',
token: this.state.sessionToken
token: this.state.sessionToken,
});
//TODO users
//TODO dashboards
}
addSimulationModel = () => {
@ -132,8 +141,8 @@ class Scenario extends React.Component {
});
}
closeDeleteModal = confirmDelete => {
this.setState({ deleteModal: false });
closeDeleteSimulationModelModal = confirmDelete => {
this.setState({ deleteSimulationModelModal: false });
if (confirmDelete === false) {
return;
@ -141,13 +150,13 @@ class Scenario extends React.Component {
AppDispatcher.dispatch({
type: 'simulationModels/start-remove',
data: this.state.modalData,
data: this.state.modalSimulationModelData,
token: this.state.sessionToken
});
}
importSimulationModel = simulationModel => {
this.setState({ importModal: false });
this.setState({ importSimulationModelModal: false });
if (simulationModel == null) {
return;
@ -155,8 +164,6 @@ class Scenario extends React.Component {
simulationModel.scenario = this.state.scenario.id;
console.log(simulationModel);
AppDispatcher.dispatch({
type: 'simulationModels/start-add',
data: simulationModel,
@ -172,6 +179,47 @@ class Scenario extends React.Component {
});
}
closeNewDashboardModal(data) {
this.setState({ newDashboardModal : false });
if (data) {
AppDispatcher.dispatch({
type: 'dashboards/start-add',
data,
token: this.state.sessionToken,
userid: this.state.sessionUserID
});
}
}
closeDeleteDashboardModal(confirmDelete){
this.setState({ deleteDashboardModal: false });
if (confirmDelete === false) {
return;
}
AppDispatcher.dispatch({
type: 'dashboards/start-remove',
data: this.state.modalDashboardData,
token: this.state.sessionToken,
userid: this.state.sessionUserID
});
}
closeImportDashboardModal(data) {
this.setState({ importDashboardModal: false });
if (data) {
AppDispatcher.dispatch({
type: 'dashboards/start-add',
data,
token: this.state.sessionToken,
userid: this.state.sessionUserID
});
}
}
getSimulatorName(simulatorId) {
for (let simulator of this.state.simulators) {
if (simulator.id === simulatorId) {
@ -184,14 +232,26 @@ class Scenario extends React.Component {
// filter properties
const model = Object.assign({}, this.state.simulationModels[index]);
delete model.simulator;
delete model.scenario;
//delete model.simulator;
//delete model.scenario;
// TODO get elements recursively
// show save dialog
const blob = new Blob([JSON.stringify(model, null, 2)], { type: 'application/json' });
FileSaver.saveAs(blob, 'simulation model - ' + model.name + '.json');
}
exportDashboard(index) {
// filter properties
const dashboard = Object.assign({}, this.state.dashboards[index]);
// TODO get elements recursively
// show save dialog
const blob = new Blob([JSON.stringify(dashboard, null, 2)], { type: 'application/json' });
FileSaver.saveAs(blob, 'dashboard - ' + dashboard.name + '.json');
}
onSimulationModelChecked(index, event) {
const selectedSimulationModels = Object.assign([], this.state.selectedSimulationModels);
for (let key in selectedSimulationModels) {
@ -250,20 +310,22 @@ class Scenario extends React.Component {
};
return <div className='section'>
<h1>{this.state.simulation.name}</h1>
<h1>{this.state.scenario.name}</h1>
{/*Simulation Model table*/}
<h2>Simulation Models</h2>
<Table data={this.state.simulationModels}>
<TableColumn checkbox onChecked={(index, event) => this.onSimulationModelChecked(index, event)} width='30' />
<TableColumn title='Name' dataKey='name' link='/simulationModel/' linkKey='_id' />
<TableColumn title='Simulator' dataKey='simulator' modifier={(simulator) => this.getSimulatorName(simulator)} />
<TableColumn title='Output' dataKey='outputLength' width='100' />
<TableColumn title='Input' dataKey='inputLength' width='100' />
<TableColumn title='Name' dataKey='name' link='/simulationModel/' linkKey='id' />
<TableColumn title='Simulator' dataKey='simulatorID' modifier={(simulatorID) => this.getSimulatorName(simulatorID)} />
<TableColumn title='Outputs' dataKey='outputLength' width='100' />
<TableColumn title='Inputs' dataKey='inputLength' width='100' />
<TableColumn
title=''
width='70'
width='200'
deleteButton
exportButton
onDelete={(index) => this.setState({ deleteModal: true, modalData: this.state.simulationModels[index], modalIndex: index })}
onDelete={(index) => this.setState({ deleteSimulationModelModal: true, modalSimulationModelData: this.state.simulationModels[index], modalSimulationModelIndex: index })}
onExport={index => this.exportModel(index)}
/>
</Table>
@ -282,14 +344,43 @@ class Scenario extends React.Component {
<div style={{ float: 'right' }}>
<Button onClick={this.addSimulationModel} style={buttonStyle}><Icon icon="plus" /> Simulation Model</Button>
<Button onClick={() => this.setState({ importModal: true })} style={buttonStyle}><Icon icon="upload" /> Import</Button>
<Button onClick={() => this.setState({ importSimulationModelModal: true })} style={buttonStyle}><Icon icon="upload" /> Import</Button>
</div>
<div style={{ clear: 'both' }} />
<ImportSimulationModelDialog show={this.state.importModal} onClose={this.importSimulationModel} simulators={this.state.simulators} />
<ImportSimulationModelDialog show={this.state.importSimulationModelModal} onClose={this.importSimulationModel} simulators={this.state.simulators} />
<DeleteDialog title="simulation model" name={this.state.modalSimulationModelData.name} show={this.state.deleteSimulationModelModal} onClose={this.closeDeleteSimulationModelModal} />
{/*Dashboard table*/}
<h2>Dashboards</h2>
<Table data={this.state.dashboards}>
<TableColumn title='Name' dataKey='name' link='/dashboards/' linkKey='id' />
<TableColumn title='Grid' dataKey='grid' />
<TableColumn
title=''
width='200'
deleteButton
exportButton
onDelete={(index) => this.setState({ deleteDashboardModal: true, modalDashboardData: this.state.dashboards[index], modalDashboardIndex: index })}
onExport={index => this.exportDashboard(index)}
/>
</Table>
<div style={{ float: 'right' }}>
<Button onClick={() => this.setState({ newDashboardModal: true })} style={buttonStyle}><Icon icon="plus" /> Dashboard</Button>
<Button onClick={() => this.setState({ importDashboardModal: true })} style={buttonStyle}><Icon icon="upload" /> Import</Button>
</div>
<div style={{ clear: 'both' }} />
<NewDashboardDialog show={this.state.newDashboardModal} onClose={data => this.closeNewDashboardModal(data)}/>
<ImportDashboardDialog show={this.state.importDashboardModal} onClose={data => this.closeImportDashboardModal(data)} />
<DeleteDialog title="dashboard" name={this.state.modalDashboardData.name} show={this.state.deleteDashboardModal} onClose={(e) => this.closeDeleteDashboardModal(e)}/>
<DeleteDialog title="simulation model" name={this.state.modalData.name} show={this.state.deleteModal} onClose={this.closeDeleteModal} />
</div>;
}
}

View file

@ -178,8 +178,8 @@ class Scenarios extends Component {
<Table data={this.state.scenarios}>
<TableColumn title='Name' dataKey='name' link='/scenarios/' linkKey='id' />
<TableColumn title='ID' dataKey='id' link='/scenarios/' linkKey='id' />
<TableColumn title='Running' dataKey='running' link='/scenarios/' linkKey='id' />
<TableColumn title='ID' dataKey='id' />
<TableColumn title='Running' dataKey='running' />
<TableColumn
width='200'
editButton

View file

@ -20,7 +20,7 @@
******************************************************************************/
import React from 'react';
import { Button, DropdownButton, DropdownItem } from 'react-bootstrap';
import { Button, ButtonToolbar, DropdownButton, DropdownItem } from 'react-bootstrap';
class SimulatorAction extends React.Component {
constructor(props) {
@ -38,7 +38,7 @@ class SimulatorAction extends React.Component {
}
}
}
setAction = id => {
// search action
for (let action of this.props.actions) {
@ -56,11 +56,13 @@ class SimulatorAction extends React.Component {
));
return <div>
<ButtonToolbar>
<DropdownButton title={this.state.selectedAction != null ? this.state.selectedAction.title : ''} id="action-dropdown" onSelect={this.setAction}>
{actionList}
{actionList}
</DropdownButton>
<Button style={{ marginLeft: '5px' }} disabled={this.props.runDisabled} onClick={() => this.props.runAction(this.state.selectedAction)}>Run</Button>
</ButtonToolbar>
</div>;
}
}