Commit 5d97e1f3 authored by Sonja Happ's avatar Sonja Happ
Browse files

started with adaptions for new package versions and new Go backend API

parent 00544c2f
......@@ -10920,6 +10920,14 @@
"react-display-name": "^0.2.0"
}
},
"react-grid-system": {
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/react-grid-system/-/react-grid-system-4.4.10.tgz",
"integrity": "sha512-ZSmQ+284QOYqDKkb5kbaFUWsuczLMQmlkAYNVv2UorG1z177UxQPYcCwmzKXpuGascksImuLpitpMpnn0UacXg==",
"requires": {
"prop-types": "^15.7.2"
}
},
"react-is": {
"version": "16.8.6",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
......
......@@ -58,7 +58,8 @@ class RestAPI {
var req = request.get(url);
if (token != null) {
req.set('x-access-token', token);
req.set('Authorization', "Bearer " + token);
}
req.end(function (error, res) {
......@@ -76,7 +77,7 @@ class RestAPI {
var req = request.post(url).send(body).timeout({ response: 5000 }); // Simple response start timeout (3s)
if (token != null) {
req.set('x-access-token', token);
req.set('Authorization', "Bearer " + token);
}
req.end(function (error, res) {
......@@ -97,7 +98,7 @@ class RestAPI {
var req = request.delete(url);
if (token != null) {
req.set('x-access-token', token);
req.set('Authorization', "Bearer " + token);
}
req.end(function (error, res) {
......@@ -115,7 +116,7 @@ class RestAPI {
var req = request.put(url).send(body);
if (token != null) {
req.set('x-access-token', token);
req.set('Authorization', "Bearer " + token);
}
req.end(function (error, res) {
......@@ -133,7 +134,7 @@ class RestAPI {
const req = request.post(url).send(data).on('progress', progressCallback);
if (token != null) {
req.set('x-access-token', token);
req.set('Authorization', "Bearer " + token);
}
req.end(function (error, res) {
......
......@@ -74,17 +74,17 @@ class EditSimulatorDialog extends React.Component {
<Dialog show={this.props.show} title="Edit Simulator" buttonTitle="Save" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
<form>
<FormGroup controlId="name">
<FormLabel>Name</FormLabel>
<FormControl type="text" placeholder={_.get(this.props.simulator, 'rawProperties.name')} value={this.state.name} onChange={(e) => this.handleChange(e)} />
<FormLabel column={false}>Name</FormLabel>
<FormControl type="text" placeholder={_.get(this.props.simulator, 'properties.name')} value={this.state.name} onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
<FormGroup controlId="endpoint">
<FormLabel>Endpoint</FormLabel>
<FormControl type="text" placeholder={_.get(this.props.simulator, 'rawProperties.endpoint')} value={this.state.endpoint || 'http://' } onChange={(e) => this.handleChange(e)} />
<FormLabel column={false}>Endpoint</FormLabel>
<FormControl type="text" placeholder={_.get(this.props.simulator, 'properties.endpoint')} value={this.state.endpoint || 'http://' } onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
<FormGroup controlId='properties'>
<FormLabel>Properties</FormLabel>
<FormLabel column={false}>Properties</FormLabel>
<ParametersEditor content={_.merge({}, this.props.simulator.rawProperties, this.props.simulator.properties)} disabled={true} />
</FormGroup>
</form>
......
......@@ -99,7 +99,7 @@ class ImportSimulationModelDialog extends React.Component {
<FormLabel>Simulator</FormLabel>
<FormControl disabled={this.imported === false} componentClass='select' placeholder='Select simulator' value={this.state.model.simulator} onChange={this.handleSimulatorChange}>
{this.props.simulators.map(simulator => (
<option key={simulator._id} value={simulator._id}>{_.get(simulator, 'properties.name') || _.get(simulator, 'rawProperties.name')}</option>
<option key={simulator.id} value={simulator.id}>{_.get(simulator, 'properties.name') || _.get(simulator, 'rawProperties.name')}</option>
))}
</FormControl>
</FormGroup>
......
......@@ -34,7 +34,8 @@ class NewUserDialog extends React.Component {
username: '',
mail: '',
role: 'admin',
password: ''
password: '',
id: 0
};
}
......@@ -57,7 +58,8 @@ class NewUserDialog extends React.Component {
username: '',
mail: '',
role: 'admin',
password: ''
password: '',
id: 0
});
}
......@@ -65,8 +67,9 @@ class NewUserDialog extends React.Component {
// check all controls
let username = this.state.username !== '' && this.state.username.length >= 3;
let password = this.state.password !== '';
let id = this.state.id !== 0;
this.valid = username && password;
this.valid = username && password && id;
// return state to control
switch(target) {
......@@ -74,6 +77,8 @@ class NewUserDialog extends React.Component {
return username ? "success" : "error";
case 'password':
return password ? "success" : "error";
case 'id':
return id ? "success" : "error";
default:
return "success";
}
......
......@@ -26,14 +26,15 @@ import { NavLink } from 'react-router-dom';
export default class HeaderMenu extends React.Component {
render() {
return <div>
<Button className="closeButton" bsStyle="link" onClick={this.props.onClose}>&times;</Button>
<Button className="closeButton" variant="link" onClick={this.props.onClose}>&times;</Button>
<ul>
<li><NavLink to="/home" activeClassName="active" title="Home" onClick={this.props.onClose}>Home</NavLink></li>
<li><NavLink to="/projects" activeClassName="active" title="Projects" onClick={this.props.onClose}>Projects</NavLink></li>
<li><NavLink to="/simulations" activeClassName="active" title="Simulations" onClick={this.props.onClose}>Simulations</NavLink></li>
<li><NavLink to="/simulators" activeClassName="active" title="Simulators" onClick={this.props.onClose}>Simulators</NavLink></li>
{ this.props.currentRole === 'admin' ?
{ this.props.currentRole === 'Admin' ?
<li><NavLink to="/users" activeClassName="active" title="User Management" onClick={this.props.onClose}>User Management</NavLink></li> : ''
}
<li><NavLink to="/logout" title="Logout" onClick={this.props.onClose}>Logout</NavLink></li>
......
......@@ -21,20 +21,25 @@
import React from 'react';
import { Col, Button } from 'react-bootstrap';
import { Hidden } from 'react-grid-system'
import Icon from './icon';
class Header extends React.Component {
render() {
return (
<header className="app-header">
<Col xs={10} smOffset={2} sm={8}>
<Col xs={{span: 10}} sm={{span: 8, offset: 2}}>
<h1>VILLASweb</h1>
</Col>
<Col xs={2} smHidden mdHidden lgHidden style={{ paddingLeft: 'auto', paddingRight: 0 }}>
{this.props.showMenuButton &&
<Button bsStyle="link" onClick={this.props.onMenuButton} style={{ float: 'right', marginRight: '10px' }}><Icon size="3x" icon="bars" className="menu-icon" /></Button>
}
</Col>
<Hidden sm md lg xl>
<Col xs={2} style={{ paddingLeft: 'auto', paddingRight: 0 }}>
{this.props.showMenuButton &&
<Button variant="link" onClick={this.props.onMenuButton} style={{ float: 'right', marginRight: '10px' }}>
<Icon size="3x" icon="bars" className="menu-icon" />
</Button>
}
</Col>
</Hidden>
</header>
);
}
......
......@@ -21,16 +21,24 @@
import React from 'react';
import { Link } from 'react-router-dom';
//import { Link } from 'react-router-dom';
import RestAPI from '../api/rest-api';
//import RestAPI from '../api/rest-api';
import config from '../config';
import UserStore from "../stores/user-store";
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {};
let currentUser = UserStore.getState().currentUser;
this.state = {
currentRole: currentUser ? currentUser.role : '',
currentUsername: currentUser ? currentUser.username: '',
currentUserID: currentUser ? currentUser.id: 0,
token: UserStore.getState().token
};
}
getCounts(type) {
......@@ -56,15 +64,21 @@ class Home extends React.Component {
VILLASweb is a frontend for distributed real-time simulation hosted by <a href={"mailto:" + config.admin.mail}>{config.admin.name}</a>.
</p>
<p>
This instance is hosting <Link to="/projects" title="Projects">{this.getCounts('projects')} projects</Link> consisting of <Link to="/simulators" title="Simulators">{this.getCounts('simulators')} simulators</Link>, {this.getCounts('visualizations')} visualizations and <Link to="/simulations" title="Simulations">{this.getCounts('simulations')} simulations</Link>.
A total of <Link to="/users" title="Users">{this.getCounts('users')} users</Link> are registered.<br />
You are logged in as user {this.state.currentUsername} with ID {this.state.currentUserID} and role {this.state.currentRole}.
</p>
{/*
<p>
This instance is hosting <Link to="/projects" title="Projects">{this.getCounts('projects')} projects</Link> consisting of <Link to="/simulators" title="Simulators">{this.getCounts('simulators')} simulators</Link>, {this.getCounts('visualizations')} visualizations and <Link to="/simulations" title="Simulations">{this.getCounts('simulations')} simulations</Link>.
A total of <Link to="/users" title="Users">{this.getCounts('users')} users</Link> are registered.<br />
</p>
*/}
<h3>Credits</h3>
<p>VILLASweb is developed by the <a href="http://acs.eonerc.rwth-aachen.de">Institute for Automation of Complex Power Systems</a> at the <a href="https;//www.rwth-aachen.de">RWTH Aachen University</a>.</p>
<ul>
<li><a href="mailto:mgrigull@eonerc.rwth-aachen.de">Markus Grigull</a></li>
<li><a href="mailto:stvogel@eonerc.rwth-aachen.de">Steffen Vogel</a></li>
<li><a href="mailto:mstevic@eonerc.rwth-aachen.de">Marija Stevic</a></li>
<li><a href="mailto:sonja.happ@eonerc.rwth-aachen.de">Sonja Happ</a></li>
</ul>
<h3>Links</h3>
<ul>
......
......@@ -61,20 +61,16 @@ class LoginForm extends Component {
render() {
return (
<Form horizontal>
<Form>
<FormGroup controlId="username">
<Col componentClass={FormLabel} sm={2}>
Username
</Col>
<FormLabel column={true} sm={2}>Username</FormLabel>
<Col sm={10}>
<FormControl type="text" placeholder="Username" onChange={(e) => this.handleChange(e)} />
</Col>
</FormGroup>
<FormGroup controlId="password">
<Col componentClass={FormLabel} sm={2}>
Password
</Col>
<FormLabel column={true} sm={2}>Password</FormLabel>
<Col sm={10}>
<FormControl type="password" placeholder="Password" onChange={(e) => this.handleChange(e)} />
</Col>
......@@ -82,14 +78,14 @@ class LoginForm extends Component {
{this.props.loginMessage &&
<div style={{ marginBottom: '50px', color: 'red' }}>
<Col smOffset={2} sm={10} style={{ paddingLeft: '5px' }}>
<Col sm={{span: 10, offset: 2}} style={{ paddingLeft: '5px' }}>
<i>Error: </i>{this.props.loginMessage}
</Col>
</div>
}
<FormGroup>
<Col smOffset={2} sm={10}>
<Col sm={{span: 10, offset: 2}}>
<Button type="submit" disabled={this.state.disableLogin} onClick={e => this.login(e)}>Login</Button>
</Col>
</FormGroup>
......
......@@ -33,7 +33,7 @@ class SidebarMenu extends React.Component {
<li><NavLink to="/projects" activeClassName="active" title="Projects">Projects</NavLink></li>
<li><NavLink to="/simulations" activeClassName="active" title="Simulations">Simulations</NavLink></li>
<li><NavLink to="/simulators" activeClassName="active" title="Simulators">Simulators</NavLink></li>
{ this.props.currentRole === 'admin' ?
{ this.props.currentRole === 'Admin' ?
<li><NavLink to="/users" activeClassName="active" title="User Management">Users</NavLink></li> : ''
}
<li><NavLink to="/logout" title="Logout">Logout</NavLink></li>
......
......@@ -36,7 +36,10 @@ class TableColumn extends Component {
clickable: false,
labelKey: null,
checkbox: false,
checkboxKey: ''
checkboxKey: '',
labelStyle: null,
labelModifier: null
};
render() {
......
......@@ -74,7 +74,7 @@ class CustomTable extends Component {
if (linkKey && data[linkKey] != null) {
cell.push(<Link to={child.props.link + data[linkKey]}>{content}</Link>);
} else if (child.props.clickable) {
cell.push(<Button bsStyle="link" onClick={() => child.props.onClick(index)}>{content}</Button>);
cell.push(<Button variant="link" onClick={() => child.props.onClick(index)}>{content}</Button>);
} else {
cell.push(content);
}
......@@ -89,7 +89,13 @@ class CustomTable extends Component {
labelContent = child.props.labelModifier(labelContent, data);
}
cell.push(<span>&nbsp;<FormLabel bsClass={child.props.labelStyle(data[labelKey], data)}>{labelContent.toString()}</FormLabel></span>);
cell.push(<span>
&nbsp;
<FormLabel column={false} classes={child.props.labelStyle(data[labelKey], data)}>
{labelContent.toString()}
</FormLabel>
</span>
);
}
if (child.props.dataIndex) {
......@@ -98,11 +104,11 @@ class CustomTable extends Component {
// add buttons
if (child.props.editButton) {
cell.push(<Button bsClass='table-control-button' onClick={() => child.props.onEdit(index)} disabled={child.props.onEdit == null}><Icon icon='edit' /></Button>);
cell.push(<Button variant='table-control-button' onClick={() => child.props.onEdit(index)} disabled={child.props.onEdit == null}><Icon icon='edit' /></Button>);
}
if (child.props.deleteButton) {
cell.push(<Button bsClass='table-control-button' onClick={() => child.props.onDelete(index)} disabled={child.props.onDelete == null}><Icon icon='trash' /></Button>);
cell.push(<Button variant='table-control-button' onClick={() => child.props.onDelete(index)} disabled={child.props.onDelete == null}><Icon icon='trash' /></Button>);
}
if (child.props.checkbox) {
......@@ -112,7 +118,7 @@ class CustomTable extends Component {
}
if (child.props.exportButton) {
cell.push(<Button bsClass='table-control-button' onClick={() => child.props.onExport(index)} disabled={child.props.onExport == null}><Icon icon='download' /></Button>);
cell.push(<Button variant='table-control-button' onClick={() => child.props.onExport(index)} disabled={child.props.onExport == null}><Icon icon='download' /></Button>);
}
return cell;
......
......@@ -26,6 +26,7 @@ import HTML5Backend from 'react-dnd-html5-backend';
import NotificationSystem from 'react-notification-system';
import { Redirect, Route } from 'react-router-dom';
import { Col } from 'react-bootstrap';
import { Hidden } from 'react-grid-system'
import AppDispatcher from '../app-dispatcher';
import SimulationStore from '../stores/simulation-store';
......@@ -63,6 +64,8 @@ class App extends React.Component {
simulators: SimulatorStore.getState(),
simulations: SimulationStore.getState(),
currentRole: currentUser ? currentUser.role : '',
currentUsername: currentUser ? currentUser.username: '',
currentUserID: UserStore.getState().userid,
token: UserStore.getState().token,
showSidebarMenu: false,
......@@ -72,6 +75,7 @@ class App extends React.Component {
componentWillMount() {
// if token stored locally, request user
const token = localStorage.getItem('token');
const userid = localStorage.getItem('userid');
if (token != null && token !== '') {
// save token so we dont logout
......@@ -79,7 +83,8 @@ class App extends React.Component {
AppDispatcher.dispatch({
type: 'users/logged-in',
token: token
token: token,
userid: userid
});
}
}
......@@ -115,17 +120,22 @@ class App extends React.Component {
return (
<DndProvider backend={HTML5Backend} >
<div>
{/*
<Col style={{ width: this.state.showSidebarMenu ? '280px' : '0px' }} smHidden mdHidden lgHidden className="sidenav">
<HeaderMenu onClose={this.hideSidebarMenu} currentRole={this.state.currentRole} />
</Col>
*/}
<Hidden sm md lg xl>
<Col style={{ width: this.state.showSidebarMenu ? '280px' : '0px' }} className="sidenav">
<HeaderMenu onClose={this.hideSidebarMenu} currentRole={this.state.currentRole} />
</Col>
</Hidden>
<div className="app">
<NotificationSystem ref="notificationSystem" />
<Header onMenuButton={this.showSidebarMenu} showMenuButton={this.state.token != null} />
<Header onMenuButton={this.showSidebarMenu} showMenuButton={false} />
<div className={`app-body app-body-spacing`} >
<Col xsHidden>
<Col xs={false}>
<SidebarMenu currentRole={this.state.currentRole} />
</Col>
......
......@@ -42,7 +42,8 @@ class Login extends Component {
return {
currentUser: UserStore.getState().currentUser,
token: UserStore.getState().token,
loginMessage: UserStore.getState().loginMessage
loginMessage: UserStore.getState().loginMessage,
userid: UserStore.getState().userid
};
}
......@@ -54,11 +55,13 @@ class Login extends Component {
// if token stored locally, request user
if (nextState.token == null) {
const token = localStorage.getItem('token');
const userid = localStorage.getItem('userid');
if (token != null && token !== '' && nextState.currentUser == null) {
AppDispatcher.dispatch({
type: 'users/logged-in',
token: token
token: token,
userid: userid
});
}
} else {
......@@ -66,6 +69,7 @@ class Login extends Component {
if (nextState.currentUser != null) {
// save login in local storage
localStorage.setItem('token', nextState.token);
localStorage.setItem('userid', nextState.userid);
}
}
}
......
......@@ -46,7 +46,7 @@ class SelectSimulator extends React.Component {
let selectedSimulator = nextProps.value;
if (selectedSimulator == null) {
if (this.state.simulators.length > 0) {
selectedSimulator = this.state.simulators[0]._id;
selectedSimulator = this.state.simulators[0].id;
} else {
selectedSimulator = '';
}
......@@ -60,7 +60,7 @@ class SelectSimulator extends React.Component {
// send complete simulator to callback
if (this.props.onChange != null) {
const simulator = this.state.simulators.find(s => s._id === event.target.value);
const simulator = this.state.simulators.find(s => s.id === event.target.value);
this.props.onChange(simulator);
}
......
......@@ -101,7 +101,7 @@ class Simulation extends React.Component {
const simulationModel = {
simulation: this.state.simulation._id,
name: 'New Simulation Model',
simulator: this.state.simulators.length > 0 ? this.state.simulators[0]._id : null,
simulator: this.state.simulators.length > 0 ? this.state.simulators[0].id : null,
outputLength: 1,
outputMapping: [{ name: 'Signal', type: 'Type' }],
inputLength: 1,
......@@ -165,7 +165,7 @@ class Simulation extends React.Component {
getSimulatorName(simulatorId) {
for (let simulator of this.state.simulators) {
if (simulator._id === simulatorId) {
if (simulator.id === simulatorId) {
return _.get(simulator, 'properties.name') || _.get(simulator, 'rawProperties.name') || simulator.uuid;
}
}
......
......@@ -66,12 +66,15 @@ class Simulators extends Component {
static calculateState() {
const simulators = SimulatorStore.getState().sort((a, b) => {
if (a.state !== b.state)
return this.statePrio(a.state) > this.statePrio(b.state);
else if (a.name !== b.name)
if (a.state !== b.state) {
return Simulators.statePrio(a.state) > Simulators.statePrio(b.state);
}
else if (a.name !== b.name) {
return a.name < b.name;
else
}
else {
return a.stateUpdatedAt < b.stateUpdatedAt;
}
});
return {
......@@ -123,6 +126,9 @@ class Simulators extends Component {
if (data) {
let simulator = this.state.simulators[this.state.modalIndex];
console.log("modalIndex: " + this.state.modalIndex);
console.log("Simulator Host:" + simulator.host);
console.log("Simulator at index 1: " + this.state.simulators[1].host)
simulator.properties = data;
this.setState({ simulator });
......@@ -151,7 +157,7 @@ class Simulators extends Component {
exportSimulator(index) {
// filter properties
let simulator = Object.assign({}, this.state.simulators[index]);
delete simulator._id;
delete simulator.id;
// show save dialog
const blob = new Blob([JSON.stringify(simulator, null, 2)], { type: 'application/json' });
......@@ -206,7 +212,7 @@ class Simulators extends Component {
}
}
isSimulatorOutdated(simulator) {
static isSimulatorOutdated(simulator) {
if (!simulator.stateUpdatedAt)
return true;
......@@ -215,10 +221,10 @@ class Simulators extends Component {
return Date.now() - new Date(simulator.stateUpdatedAt) > fiveMinutes;
}
stateLabelStyle = (state, simulator) => {
static stateLabelStyle(state, simulator){
var style = [ 'label' ];
if (this.isSimulatorOutdated(simulator) && state !== 'shutdown') {
if (Simulators.isSimulatorOutdated(simulator) && state !== 'shutdown') {
style.push('label-outdated');
}
......@@ -250,7 +256,7 @@ class Simulators extends Component {
return style.join(' ');
}
stateUpdateModifier = updatedAt => {
static stateUpdateModifier(updatedAt) {
const date = new Date(updatedAt);
return date.toLocaleString('de-DE');
......@@ -268,15 +274,15 @@ class Simulators extends Component {
<Table data={this.state.simulators}>
<TableColumn checkbox onChecked={(index, event) => this.onSimulatorChecked(index, event)} width='30' />
<TableColumn title='Name' dataKeys={['properties.name', 'rawProperties.name']} />
<TableColumn title='State' labelKey='state' tooltipKey='error' labelModifier={this.stateLabelModifier} labelStyle={this.stateLabelStyle} />
<TableColumn title='State' labelKey='state' tooltipKey='error' labelModifier={Simulators.stateLabelModifier} labelStyle={Simulators.stateLabelStyle} />
<TableColumn title='Category' dataKeys={['properties.category', 'rawProperties.category']} />
<TableColumn title='Type' dataKeys={['properties.type', 'rawProperties.type']} />
<TableColumn title='Location' dataKeys={['properties.location', 'rawProperties.location']} />
{/* <TableColumn title='Realm' dataKeys={['properties.realm', 'rawProperties.realm']} /> */}
<TableColumn title='Host' dataKey='host' />
<TableColumn title='Last Update' dataKey='stateUpdatedAt' modifier={this.stateUpdateModifier} />
<TableColumn title='Last Update' dataKey='stateUpdatedAt' modifier={Simulators.stateUpdateModifier} />
<TableColumn
width='100'
width='200'
editButton
exportButton