Commit 79549494 authored by Sonja Happ's avatar Sonja Happ

Merge branch 'new-api' into develop

parents 31d56953 7331bf51
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,47 +3,52 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.8",
"@fortawesome/free-solid-svg-icons": "^5.5.0",
"@fortawesome/react-fontawesome": "^0.1.3",
"@fortawesome/fontawesome-svg-core": "^1.2.19",
"@fortawesome/free-solid-svg-icons": "^5.9.0",
"@fortawesome/react-fontawesome": "^0.1.4",
"babel-runtime": "^6.26.0",
"bootstrap": "^3.3.7",
"bootstrap": "^4.3.1",
"classnames": "^2.2.6",
"d3-array": "^1.2.4",
"d3-array": "^2.2.0",
"d3-axis": "^1.0.12",
"d3-scale": "^1.0.6",
"d3-selection": "^1.3.2",
"d3-shape": "^1.2.2",
"d3-scale": "^3.0.0",
"d3-scale-chromatic": "^1.3.3",
"d3-selection": "^1.4.0",
"d3-shape": "^1.3.5",
"d3-time-format": "^2.1.3",
"es6-promise": "^4.2.5",
"file-saver": "^1.3.8",
"flux": "^3.1.2",
"gaugeJS": "^1.3.2",
"handlebars": "^4.1.1",
"immutable": "^3.8.1",
"jszip": "^3.2.0",
"es6-promise": "^4.2.8",
"file-saver": "^2.0.2",
"flux": "^3.1.3",
"frontend-collective-react-dnd-scrollzone": "^1.0.2",
"gaugeJS": "^1.3.7",
"handlebars": "^4.5.1",
"immutable": "^4.0.0-rc.12",
"jquery": "^3.4.1",
"jszip": "^3.2.2",
"libcimsvg": "git+https://git.rwth-aachen.de/acs/public/cim/pintura-npm-package.git",
"lodash": "^4.17.11",
"prop-types": "^15.6.2",
"rc-slider": "^8.6.3",
"react": "^16.6.3",
"react-bootstrap": "^0.31.1",
"react-contexify": "^3.0.3",
"lodash": "^4.17.15",
"prop-types": "^15.7.2",
"rc-slider": "^8.6.13",
"react": "^16.8.6",
"react-bootstrap": "^1.0.0-beta.9",
"react-contexify": "^4.1.1",
"react-d3": "^0.4.0",
"react-dnd": "^2.6.0",
"react-dnd-html5-backend": "^2.6.0",
"react-dom": "^16.6.3",
"react-fullscreenable": "^2.5.0",
"react-dnd": "^9.3.2",
"react-dnd-html5-backend": "^9.3.2",
"react-dom": "^16.8.6",
"react-fullscreenable": "^2.5.1-0",
"react-grid-system": "^4.4.10",
"react-json-view": "^1.19.1",
"react-notification-system": "^0.2.17",
"react-rnd": "^7.4.3",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-rnd": "^10.0.0",
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-scripts": "^3.0.1",
"react-sortable-tree": "^0.1.19",
"react-svg-pan-zoom": "^2.18.0",
"superagent": "^3.8.3",
"validator": "^10.9.0"
"react-sortable-tree": "^2.6.2",
"react-svg-pan-zoom": "^3.1.0",
"superagent": "^5.1.0",
"typescript": "^3.5.3",
"validator": "^11.1.0"
},
"devDependencies": {
"chai": "^4.2.0"
......
import { expect } from 'chai';
import createControls from '../../../components/dialogs/edit-widget-control-creator';
import EditWidgetTextControl from '../../../components/dialogs/edit-widget-text-control';
import EditWidgetColorControl from '../../../components/dialogs/edit-widget-color-control';
import EditWidgetTimeControl from '../../../components/dialogs/edit-widget-time-control';
import EditImageWidgetControl from '../../../components/dialogs/edit-widget-image-control';
import EditWidgetSimulationControl from '../../../components/dialogs/edit-widget-simulation-control';
import EditWidgetSignalControl from '../../../components/dialogs/edit-widget-signal-control';
import EditWidgetSignalsControl from '../../../components/dialogs/edit-widget-signals-control';
import EditWidgetOrientation from '../../../components/dialogs/edit-widget-orientation';
import EditWidgetTextSizeControl from '../../../components/dialogs/edit-widget-text-size-control';
import EditWidgetAspectControl from '../../../components/dialogs/edit-widget-aspect-control';
import EditWidgetCheckboxControl from '../../../components/dialogs/edit-widget-checkbox-control';
import EditWidgetMinMaxControl from '../../../components/dialogs/edit-widget-min-max-control';
import EditWidgetColorZonesControl from '../../../components/dialogs/edit-widget-color-zones-control';
import EditWidgetHTMLContent from '../../../components/dialogs/edit-widget-html-content';
import EditWidgetNumberControl from '../../../components/dialogs/edit-widget-number-control';
import createControls from '../../widget/edit-widget-control-creator';
import EditWidgetTextControl from '../../widget/edit-widget-text-control';
import EditWidgetColorControl from '../../widget/edit-widget-color-control';
import EditWidgetTimeControl from '../../widget/edit-widget-time-control';
import EditImageWidgetControl from '../../widget/edit-widget-image-control';
import EditWidgetSimulationControl from '../../widget/edit-widget-simulation-control';
import EditWidgetSignalControl from '../../widget/edit-widget-signal-control';
import EditWidgetSignalsControl from '../../widget/edit-widget-signals-control';
import EditWidgetOrientation from '../../widget/edit-widget-orientation';
import EditWidgetTextSizeControl from '../../widget/edit-widget-text-size-control';
import EditWidgetAspectControl from '../../widget/edit-widget-aspect-control';
import EditWidgetCheckboxControl from '../../widget/edit-widget-checkbox-control';
import EditWidgetMinMaxControl from '../../widget/edit-widget-min-max-control';
import EditWidgetColorZonesControl from '../../widget/edit-widget-color-zones-control';
import EditWidgetHTMLContent from '../../widget/edit-widget-html-content';
import EditWidgetNumberControl from '../../widget/edit-widget-number-control';
describe('edit widget control creator', () => {
it('should not return null', () => {
......
......@@ -21,38 +21,43 @@
import React from 'react';
import { Container } from 'flux/utils';
import { DragDropContext } from 'react-dnd';
import { DndProvider } from 'react-dnd';
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 AppDispatcher from '../app-dispatcher';
import SimulationStore from '../stores/simulation-store';
import SimulatorStore from '../stores/simulator-store';
import UserStore from '../stores/user-store';
import NotificationsDataManager from '../data-managers/notifications-data-manager';
import Home from '../components/home';
import Header from '../components/header';
import Footer from '../components/footer';
import SidebarMenu from '../components/menu-sidebar';
import HeaderMenu from '../components/header-menu';
import Projects from './projects';
import Project from './project';
import Simulators from './simulators';
import Visualization from './visualization';
import Simulations from './simulations';
import Simulation from './simulation';
import SimulationModel from './simulation-model';
import Users from './users';
import '../styles/app.css';
import { Hidden } from 'react-grid-system'
import AppDispatcher from './common/app-dispatcher';
import ScenarioStore from './scenario/scenario-store';
import SimulatorStore from './simulator/simulator-store';
import UserStore from './user/user-store';
import NotificationsDataManager from './common/data-managers/notifications-data-manager';
import Home from './common/home';
import Header from './common/header';
import Footer from './common/footer';
import SidebarMenu from './common/menu-sidebar';
import HeaderMenu from './common/header-menu';
//import Projects from './project/projects';
//import Project from './project/project';
import Simulators from './simulator/simulators';
import Dashboard from './dashboard/dashboard';
//import Simulations from './simulation/simulations';
//import Simulation from './simulation/simulation';
import Scenarios from './scenario/scenarios';
import Scenario from './scenario/scenario';
import SimulationModel from './simulationmodel/simulation-model';
import Users from './user/users';
import User from './user/user';
import './styles/app.css';
class App extends React.Component {
static getStores() {
return [ SimulatorStore, UserStore, SimulationStore ];
return [ SimulatorStore, UserStore, ScenarioStore];
}
static calculateState(prevState) {
......@@ -60,8 +65,10 @@ class App extends React.Component {
return {
simulators: SimulatorStore.getState(),
simulations: SimulationStore.getState(),
scenarios: ScenarioStore.getState(),
currentRole: currentUser ? currentUser.role : '',
currentUsername: currentUser ? currentUser.username: '',
currentUserID: UserStore.getState().userid,
token: UserStore.getState().token,
showSidebarMenu: false,
......@@ -71,6 +78,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
......@@ -78,20 +86,21 @@ class App extends React.Component {
AppDispatcher.dispatch({
type: 'users/logged-in',
token: token
token: token,
userid: userid
});
}
}
componentDidMount() {
// load all simulators and simulations to fetch simulation data
// load all simulators and scenarios to fetch data
AppDispatcher.dispatch({
type: 'simulators/start-load',
token: this.state.token
});
AppDispatcher.dispatch({
type: 'simulations/start-load',
type: 'scenarios/start-load',
token: this.state.token
});
......@@ -100,11 +109,11 @@ class App extends React.Component {
showSidebarMenu = () => {
this.setState({ showSidebarMenu: true });
}
};
hideSidebarMenu = () => {
this.setState({ showSidebarMenu: false });
}
};
render() {
if (this.state.token == null) {
......@@ -112,40 +121,54 @@ class App extends React.Component {
}
return (
<div>
<Col style={{ width: this.state.showSidebarMenu ? '280px' : '0px' }} smHidden mdHidden lgHidden className="sidenav">
<HeaderMenu onClose={this.hideSidebarMenu} currentRole={this.state.currentRole} />
</Col>
<div className="app">
<NotificationSystem ref="notificationSystem" />
<Header onMenuButton={this.showSidebarMenu} showMenuButton={this.state.token != null} />
<div className={`app-body app-body-spacing`} >
<Col xsHidden>
<SidebarMenu currentRole={this.state.currentRole} />
<DndProvider backend={HTML5Backend} >
<div>
{/*
<Col style={{ width: this.state.showSidebarMenu ? '280px' : '0px' }} smHidden mdHidden lgHidden className="sidenav">
*/}
<Hidden sm md lg xl>
<Col style={{ width: this.state.showSidebarMenu ? '280px' : '0px' }} className="sidenav">
<HeaderMenu onClose={this.hideSidebarMenu} currentRole={this.state.currentRole} />
</Col>
<div className={`app-content app-content-margin-left`}>
<Route exact path="/" component={Home} />
<Route path="/home" component={Home} />
<Route exact path="/projects" component={Projects} />
<Route path="/projects/:project" component={Project} />
<Route path="/visualizations/:visualization" component={Visualization} />
<Route exact path="/simulations" component={Simulations} />
<Route path="/simulations/:simulation" component={Simulation} />
<Route path="/simulationModel/:simulationModel" component={SimulationModel} />
<Route path="/simulators" component={Simulators} />
<Route path="/users" component={Users} />
</Hidden>
<div className="app">
<NotificationSystem ref="notificationSystem" />
<Header onMenuButton={this.showSidebarMenu} showMenuButton={false} />
<div className={`app-body app-body-spacing`} >
<Col xs={false}>
<SidebarMenu currentRole={this.state.currentRole} />
</Col>
<div className={`app-content app-content-margin-left`}>
<Route exact path="/" component={Home} />
<Route path="/home" component={Home} />
<Route path="/dashboards/:dashboard" component={Dashboard} />
<Route exact path="/scenarios" component={Scenarios} />
<Route path="/scenarios/:scenario" component={Scenario} />
<Route path="/simulationModel/:simulationModel" component={SimulationModel} />
<Route path="/simulators" component={Simulators} />
<Route path="/user" component={User} />
<Route path="/users" component={Users} />
</div>
</div>
</div>
<Footer />
<Footer />
</div>
</div>
</div>
);
</DndProvider>
)
}
}
export default DragDropContext(HTML5Backend)(Container.create(App));
// Removed routes
//<Route exact path="/projects" component={Projects} />
//<Route path="/projects/:project" component={Project} />
//<Route exact path="/simulations" component={Simulations} />
//<Route path="/simulations/:simulation" component={Simulation} />
let fluxContainerConverter = require('./common/FluxContainerConverter');
export default Container.create(fluxContainerConverter.convert(App));
//DragDropContext(HTML5Backend)(Container.create(App));
/// FluxContainerConverter.js
/// This is an ugly workaround found here https://github.com/facebook/flux/issues/351 to make Flux Containers work with ES6
module.exports = {
convert: function(containerClass) {
const tmp = containerClass;
containerClass = function(...args) {
return new tmp(...args);
};
containerClass.prototype = tmp.prototype;
containerClass.getStores = tmp.getStores;
containerClass.calculateState = tmp.calculateState;
return containerClass;
}
};
......@@ -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) {
......
......@@ -21,7 +21,8 @@
import { ReduceStore } from 'flux/utils';
import AppDispatcher from '../app-dispatcher';
import AppDispatcher from './app-dispatcher';
import NotificationsDataManager from '../common/data-managers/notifications-data-manager';
class ArrayStore extends ReduceStore {
constructor(type, dataManager) {
......@@ -39,7 +40,7 @@ class ArrayStore extends ReduceStore {
// search for existing element to update
state.forEach((element, index, array) => {
newElements = newElements.filter((updateElement, newIndex) => {
if (element._id === updateElement._id) {
if (element.id === updateElement.id) {
// update each property
for (var key in updateElement) {
if (updateElement.hasOwnProperty(key)) {
......@@ -67,6 +68,7 @@ class ArrayStore extends ReduceStore {
reduce(state, action) {
switch (action.type) {
case this.type + '/start-load':
if (Array.isArray(action.data)) {
action.data.forEach((id) => {
this.dataManager.load(id, action.token);
......@@ -84,9 +86,18 @@ class ArrayStore extends ReduceStore {
}
case this.type + '/load-error':
// TODO: Add error message
return state;
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);
return state;
......@@ -95,8 +106,9 @@ class ArrayStore extends ReduceStore {
return this.updateElements(state, [action.data]);
case this.type + '/add-error':
// TODO: Add error message
return state;
return state;
case this.type + '/start-remove':
this.dataManager.remove(action.data, action.token);
......@@ -108,20 +120,41 @@ class ArrayStore extends ReduceStore {
});
case this.type + '/remove-error':
// TODO: Add error message
if (action.error && !action.error.handled && action.error.response) {
const USER_REMOVE_ERROR_NOTIFICATION = {
title: 'Failed to add remove ',
message: action.error.response.body.message,
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);
return state;
case this.type + '/start-edit':
case this.type + '/start-own-edit':
this.dataManager.update(action.data, action.token);
return state;
case this.type + '/edited':
return this.updateElements(state, [action.data]);
case this.type + '/edit-error':
// TODO: Add error message
case this.type + '/confirm-pw-doesnt-match':
const USER_PW_ERROR_NOTIFICATION = {
title: 'The new password does not match',
message: 'Try again',
level: 'error'
};
NotificationsDataManager.addNotification(USER_PW_ERROR_NOTIFICATION);
return state;
case this.type + '/edit-error':
return state;
default:
return state;
}
......
......@@ -22,7 +22,7 @@
import RestAPI from '../api/rest-api';
import AppDispatcher from '../app-dispatcher';
const API_URL = '/api/v1';
const API_URL = '/api/v2';
class RestDataManager {
constructor(type, url, keyFilter) {
......@@ -114,7 +114,7 @@ class RestDataManager {
}
remove(object, token = null) {
RestAPI.delete(this.makeURL(this.url + '/' + object._id), token).then(response => {
RestAPI.delete(this.makeURL(this.url + '/' + object.id), token).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/removed',
data: response[this.type],
......@@ -132,7 +132,7 @@ class RestDataManager {
var obj = {};
obj[this.type] = this.filterKeys(object);
RestAPI.put(this.makeURL(this.url + '/' + object._id), obj, token).then(response => {
RestAPI.put(this.makeURL(this.url + '/' + object.id), obj, token).then(response => {
AppDispatcher.dispatch({
type: this.type + 's/edited',
data: response[this.type]
......
......@@ -43,7 +43,7 @@ class DeleteDialog extends React.Component {
<Modal.Footer>
<Button onClick={() => this.props.onClose(false)}>Cancel</Button>
<Button bsStyle="danger" onClick={() => this.props.onClose(true)}>Delete</Button>
<Button variant="danger" onClick={() => this.props.onClose(true)}>Delete</Button>
</Modal.Footer>
</Modal>;
}
......
......@@ -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