mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Merge branch 'fix-router' into 'develop'
Fix router See merge request acs/public/villas/web!61
This commit is contained in:
commit
c7af7bd82e
12 changed files with 112 additions and 52 deletions
17
src/app.js
17
src/app.js
|
@ -87,8 +87,13 @@ class App extends React.Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
if (this.state.token == null) {
|
||||
return (<Redirect to="/login" />);
|
||||
|
||||
let token = localStorage.getItem("token");
|
||||
let currentUser = JSON.parse(localStorage.getItem("currentUser"));
|
||||
|
||||
if (token == null || currentUser == null) {
|
||||
console.log("APP redirecting to logout/ login")
|
||||
return (<Redirect to="/logout" />);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -99,7 +104,7 @@ class App extends React.Component {
|
|||
*/}
|
||||
<Hidden sm md lg xl>
|
||||
<Col style={{ width: this.state.showSidebarMenu ? '280px' : '0px' }} className="sidenav">
|
||||
<HeaderMenu onClose={this.hideSidebarMenu} currentRole={this.state.currentUser.role} />
|
||||
<HeaderMenu onClose={this.hideSidebarMenu} currentRole={currentUser.role} />
|
||||
</Col>
|
||||
</Hidden>
|
||||
|
||||
|
@ -110,17 +115,17 @@ class App extends React.Component {
|
|||
|
||||
<div className={`app-body app-body-spacing`} >
|
||||
<Col xs={false}>
|
||||
<SidebarMenu currentRole={this.state.currentUser.role} />
|
||||
<SidebarMenu currentRole={currentUser.role} />
|
||||
</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="/dashboards/:dashboard" component={Dashboard} />
|
||||
<Route path="/infrastructure" component={InfrastructureComponents} />
|
||||
<Route path="/user" component={User} />
|
||||
<Route path="/account" component={User} />
|
||||
<Route path="/users" component={Users} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -27,11 +27,12 @@ export default class HeaderMenu extends React.Component {
|
|||
|
||||
<ul>
|
||||
<li><NavLink to="/home" activeClassName="active" title="Home" onClick={this.props.onClose}>Home</NavLink></li>
|
||||
<li><NavLink to="/scenario" activeClassName="active" title="Scenarios" onClick={this.props.onClose}>Scenarios</NavLink></li>
|
||||
<li><NavLink to="/scenarios" activeClassName="active" title="Scenarios" onClick={this.props.onClose}>Scenarios</NavLink></li>
|
||||
<li><NavLink to="/infrastructure" activeClassName="active" title="Infrastructure Components" onClick={this.props.onClose}>Infrastructure Components</NavLink></li>
|
||||
{ this.props.currentRole === 'Admin' ?
|
||||
<li><NavLink to="/users" activeClassName="active" title="User Management" onClick={this.props.onClose}>User Management</NavLink></li> : ''
|
||||
}
|
||||
<li><NavLink to="/account" title="Account">Account</NavLink></li>
|
||||
<li><NavLink to="/logout" title="Logout" onClick={this.props.onClose}>Logout</NavLink></li>
|
||||
</ul>
|
||||
</div>;
|
||||
|
|
|
@ -19,6 +19,7 @@ import React from 'react';
|
|||
|
||||
import config from '../config';
|
||||
import LoginStore from "../user/login-store";
|
||||
import {Redirect} from "react-router-dom";
|
||||
|
||||
class Home extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -38,6 +39,13 @@ class Home extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
|
||||
let currentUser = JSON.parse(localStorage.getItem("currentUser"));
|
||||
if (currentUser == null){
|
||||
console.log("HOME redirecting to logout/ login")
|
||||
return (<Redirect to="/logout" />);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="home-container">
|
||||
<img style={{height: 120, float: 'right'}} src={require('../img/villas_web.svg')} alt="Logo VILLASweb" />
|
||||
|
@ -47,7 +55,7 @@ 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>
|
||||
You are logged in as user <b>{this.state.currentUser.username}</b> with <b>ID {this.state.currentUser.id}</b> and role <b>{this.state.currentUser.role}</b>.
|
||||
You are logged in as user <b>{currentUser.username}</b> with <b>ID {currentUser.id}</b> and role <b>{currentUser.role}</b>.
|
||||
</p>
|
||||
|
||||
<h3>Data Model</h3>
|
||||
|
|
|
@ -31,7 +31,7 @@ class SidebarMenu extends React.Component {
|
|||
{ this.props.currentRole === 'Admin' ?
|
||||
<li><NavLink to="/users" activeClassName="active" title="User Management">User Management</NavLink></li> : ''
|
||||
}
|
||||
<li><NavLink to="/user" title="Account">Account</NavLink></li>
|
||||
<li><NavLink to="/account" title="Account">Account</NavLink></li>
|
||||
<li><NavLink to="/logout" title="Logout">Logout</NavLink></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -28,7 +28,6 @@ import WidgetToolbox from '../widget/widget-toolbox';
|
|||
import WidgetArea from '../widget/widget-area';
|
||||
import DashboardButtonGroup from './dashboard-button-group';
|
||||
|
||||
import LoginStore from '../user/login-store';
|
||||
import DashboardStore from './dashboard-store';
|
||||
import SignalStore from '../signal/signal-store'
|
||||
import FileStore from '../file/file-store';
|
||||
|
@ -42,8 +41,9 @@ import 'react-contexify/dist/ReactContexify.min.css';
|
|||
class Dashboard extends Component {
|
||||
|
||||
static lastWidgetKey = 0;
|
||||
static webSocketsOpened = false;
|
||||
static getStores() {
|
||||
return [ DashboardStore, LoginStore,FileStore, WidgetStore, SignalStore, ConfigStore, ICStore];
|
||||
return [ DashboardStore, FileStore, WidgetStore, SignalStore, ConfigStore, ICStore];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
@ -51,7 +51,7 @@ class Dashboard extends Component {
|
|||
prevState = {};
|
||||
}
|
||||
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
const sessionToken = localStorage.getItem("token");
|
||||
|
||||
let dashboard = DashboardStore.getState().find(d => d.id === parseInt(props.match.params.dashboard, 10));
|
||||
if (dashboard == null){
|
||||
|
@ -73,20 +73,22 @@ class Dashboard extends Component {
|
|||
|
||||
return thisWidgetHeight > maxHeightSoFar? thisWidgetHeight : maxHeightSoFar;
|
||||
}, 0);
|
||||
if(dashboard.height === 0){
|
||||
dashboard.height = 400;
|
||||
}
|
||||
else if(maxHeight + 80 > dashboard.height)
|
||||
{
|
||||
dashboard.height = maxHeight + 80;
|
||||
}
|
||||
|
||||
|
||||
// filter component configurations to the ones that belong to this scenario
|
||||
let configs = []
|
||||
let files = []
|
||||
if (dashboard !== null) {
|
||||
if (dashboard !== undefined) {
|
||||
configs = ConfigStore.getState().filter(config => config.scenarioID === dashboard.scenarioID);
|
||||
files = FileStore.getState().filter(file => file.scenarioID === dashboard.scenarioID);
|
||||
|
||||
if(dashboard.height === 0){
|
||||
dashboard.height = 400;
|
||||
}
|
||||
else if(maxHeight + 80 > dashboard.height)
|
||||
{
|
||||
dashboard.height = maxHeight + 80;
|
||||
}
|
||||
}
|
||||
|
||||
// filter signals to the ones belonging to the scenario at hand
|
||||
|
@ -154,18 +156,46 @@ class Dashboard extends Component {
|
|||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-load',
|
||||
token: this.state.sessionToken,
|
||||
param: '?dashboardID=' + this.state.dashboard.id
|
||||
param: '?dashboardID=' + parseInt(this.props.match.params.dashboard, 10),
|
||||
});
|
||||
|
||||
// open web sockets if ICs are already known
|
||||
if(this.state.ics.length > 0){
|
||||
// load ICs to enable that component configs and dashboards work with them
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/start-load',
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot: SS) {
|
||||
// open web sockets if ICs are already known and sockets are not opened yet
|
||||
if(!Dashboard.webSocketsOpened && this.state.ics.length > 0){
|
||||
console.log("Starting to open IC websockets:", this.state.ics);
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/open-sockets',
|
||||
data: this.state.ics
|
||||
});
|
||||
} else {
|
||||
console.log("ICs unknown in componentDidMount", this.state.dashboard)
|
||||
|
||||
Dashboard.webSocketsOpened = true;
|
||||
}
|
||||
|
||||
if(this.state.configs.length === 0 && this.state.dashboard !== undefined) {
|
||||
// load configs
|
||||
AppDispatcher.dispatch({
|
||||
type: 'configs/start-load',
|
||||
token: this.state.sessionToken,
|
||||
param: '?scenarioID=' + this.state.dashboard.scenarioID
|
||||
});
|
||||
}
|
||||
|
||||
if(this.state.files.length === 0 && this.state.dashboard !== undefined){
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-load',
|
||||
param: '?scenarioID=' + this.state.dashboard.scenarioID,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -398,6 +428,10 @@ class Dashboard extends Component {
|
|||
|
||||
|
||||
render() {
|
||||
if (this.state.dashboard === undefined){
|
||||
return <div className="section-title"> <span>{"Loading Dashboard..."}</span> </div>
|
||||
}
|
||||
|
||||
const grid = this.state.dashboard.grid;
|
||||
const boxClasses = classNames('section', 'box', { 'fullscreen-padding': this.props.isFullscreen });
|
||||
let draggable = this.state.editing;
|
||||
|
|
|
@ -75,7 +75,7 @@ class InfrastructureComponents extends Component {
|
|||
});
|
||||
|
||||
return {
|
||||
sessionToken: LoginStore.getState().token,
|
||||
sessionToken: localStorage.getItem("token"),
|
||||
ics: ics,
|
||||
modalIC: {},
|
||||
deleteModal: false,
|
||||
|
|
|
@ -21,6 +21,13 @@ import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
|||
import App from './app';
|
||||
import Login from './user/login';
|
||||
import Logout from './user/logout';
|
||||
import Home from './common/home';
|
||||
import Scenarios from './scenario/scenarios';
|
||||
import Scenario from './scenario/scenario';
|
||||
import Dashboard from './dashboard/dashboard'
|
||||
import InfrastructureComponents from './ic/ics';
|
||||
import Users from './user/users';
|
||||
import User from "./user/user";
|
||||
|
||||
class Root extends React.Component {
|
||||
render() {
|
||||
|
@ -30,6 +37,14 @@ class Root extends React.Component {
|
|||
<Route path='/login' component={Login} />
|
||||
<Route path='/logout' component={Logout} />
|
||||
<Route path='/' component={App} />
|
||||
<Route path='/home' component={Home} />
|
||||
<Route path='/scenarios' component={Scenarios} />
|
||||
<Route path='/scenarios/:scenario' component={Scenario} />
|
||||
<Route path='/dashboards/:dashboard' component={Dashboard} />
|
||||
<Route path='/infrastructure' component={InfrastructureComponents} />
|
||||
<Route path='/users' component={Users} />
|
||||
<Route path='/account' component={User} />
|
||||
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
|
|
@ -25,7 +25,6 @@ import ScenarioStore from './scenario-store';
|
|||
import ICStore from '../ic/ic-store';
|
||||
import DashboardStore from '../dashboard/dashboard-store';
|
||||
import ConfigStore from '../componentconfig/config-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import SignalStore from '../signal/signal-store'
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
|
||||
|
@ -48,7 +47,7 @@ import WidgetStore from "../widget/widget-store";
|
|||
class Scenario extends React.Component {
|
||||
|
||||
static getStores() {
|
||||
return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore];
|
||||
return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, SignalStore, FileStore, WidgetStore];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
@ -57,10 +56,10 @@ class Scenario extends React.Component {
|
|||
}
|
||||
|
||||
// get selected scenario
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
const sessionToken = localStorage.getItem("token");
|
||||
|
||||
const scenario = ScenarioStore.getState().find(s => s.id === parseInt(props.match.params.scenario, 10));
|
||||
if (scenario == null) {
|
||||
if (scenario === undefined) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-load',
|
||||
data: props.match.params.scenario,
|
||||
|
@ -118,14 +117,14 @@ class Scenario extends React.Component {
|
|||
//load selected scenario
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-load',
|
||||
data: this.state.scenario.id,
|
||||
data: parseInt(this.props.match.params.scenario, 10),
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-load-users',
|
||||
data: this.state.scenario.id,
|
||||
data: parseInt(this.props.match.params.scenario, 10),
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
|
||||
|
@ -418,7 +417,7 @@ class Scenario extends React.Component {
|
|||
this.setState({editOutputSignalsModal: false});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onEditFiles(){
|
||||
let tempFiles = [];
|
||||
this.state.files.forEach( file => {
|
||||
|
@ -508,10 +507,14 @@ class Scenario extends React.Component {
|
|||
|
||||
const iconStyle = {
|
||||
color: '#007bff',
|
||||
height: '25px',
|
||||
height: '25px',
|
||||
width : '25px'
|
||||
}
|
||||
|
||||
if(this.state.scenario === undefined){
|
||||
return <h1>Loading Scenario...</h1>;
|
||||
}
|
||||
|
||||
return <div className='section'>
|
||||
<div className='section-buttons-group-right'>
|
||||
<OverlayTrigger key={0} placement={'bottom'} overlay={<Tooltip id={`tooltip-${"file"}`}> Add, edit or delete files of scenario </Tooltip>} >
|
||||
|
@ -655,7 +658,7 @@ class Scenario extends React.Component {
|
|||
<h2 style={tableHeadingStyle}>Users sharing this scenario</h2>
|
||||
<div>
|
||||
<Table data={this.state.scenario.users}>
|
||||
<TableColumn title='Name' dataKey='username' link='/users/' linkKey='id' />
|
||||
<TableColumn title='Name' dataKey='username'/>
|
||||
<TableColumn title='Mail' dataKey='mail' />
|
||||
<TableColumn
|
||||
title=''
|
||||
|
|
|
@ -22,7 +22,6 @@ 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';
|
||||
|
@ -41,7 +40,7 @@ import DeleteDialog from '../common/dialogs/delete-dialog';
|
|||
class Scenarios extends Component {
|
||||
|
||||
static getStores() {
|
||||
return [ScenarioStore, LoginStore, DashboardStore, WidgetStore, ConfigStore, SignalStore];
|
||||
return [ScenarioStore, DashboardStore, WidgetStore, ConfigStore, SignalStore];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
|
@ -50,7 +49,7 @@ class Scenarios extends Component {
|
|||
scenarios: ScenarioStore.getState(),
|
||||
dashboards: DashboardStore.getState(),
|
||||
configs: ConfigStore.getState(),
|
||||
sessionToken: LoginStore.getState().token,
|
||||
sessionToken: localStorage.getItem("token"),
|
||||
|
||||
newModal: false,
|
||||
deleteModal: false,
|
||||
|
|
|
@ -73,7 +73,7 @@ class Login extends Component {
|
|||
|
||||
render() {
|
||||
if (this.state.currentUser != null) {
|
||||
return (<Redirect to="/" />);
|
||||
return (<Redirect to="/home" />);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -20,10 +20,8 @@ import { Container } from 'flux/utils';
|
|||
import {Button, Col, Row} from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import LoginStore from './login-store';
|
||||
import UsersStore from './users-store';
|
||||
|
||||
|
||||
import Icon from '../common/icon';
|
||||
import EditOwnUserDialog from './edit-own-user'
|
||||
import NotificationsDataManager from "../common/data-managers/notifications-data-manager"
|
||||
|
@ -31,17 +29,15 @@ import NotificationsDataManager from "../common/data-managers/notifications-data
|
|||
|
||||
class User extends Component {
|
||||
static getStores() {
|
||||
return [ LoginStore, UsersStore ];
|
||||
return [ UsersStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
prevState = prevState || {};
|
||||
|
||||
let user = LoginStore.getState().currentUser;
|
||||
|
||||
return {
|
||||
currentUser: user,
|
||||
token: LoginStore.getState().token,
|
||||
currentUser: JSON.parse(localStorage.getItem("currentUser")),
|
||||
token: localStorage.getItem("token"),
|
||||
editModal: false,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import { Container } from 'flux/utils';
|
|||
import { Button } from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import LoginStore from './login-store';
|
||||
import UsersStore from './users-store';
|
||||
|
||||
import Icon from '../common/icon';
|
||||
|
@ -34,23 +33,23 @@ import NotificationsDataManager from "../common/data-managers/notifications-data
|
|||
|
||||
class Users extends Component {
|
||||
static getStores() {
|
||||
return [ LoginStore, UsersStore ];
|
||||
return [ UsersStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
||||
let tokenState = LoginStore.getState().token;
|
||||
let token = localStorage.getItem("token");
|
||||
|
||||
// If there is a token available and this method was called as a result of loading users
|
||||
if (!prevState && tokenState) {
|
||||
if (!prevState && token) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/start-load',
|
||||
token: tokenState
|
||||
token: token
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
token: tokenState,
|
||||
token: token,
|
||||
users: UsersStore.getState(),
|
||||
|
||||
newModal: false,
|
||||
|
|
Loading…
Add table
Reference in a new issue