mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
merge example-dashboard
This commit is contained in:
commit
8066cbb19c
76 changed files with 5932 additions and 3842 deletions
7374
package-lock.json
generated
7374
package-lock.json
generated
File diff suppressed because it is too large
Load diff
55
package.json
55
package.json
|
@ -3,51 +3,54 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
||||
"@fortawesome/react-fontawesome": "^0.1.4",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
||||
"@fortawesome/react-fontawesome": "^0.1.8",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"bootstrap": "^4.3.1",
|
||||
"bootstrap": "^4.4.1",
|
||||
"classnames": "^2.2.6",
|
||||
"d3-array": "^2.2.0",
|
||||
"d3-array": "^2.4.0",
|
||||
"d3-axis": "^1.0.12",
|
||||
"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",
|
||||
"d3-scale": "^3.2.1",
|
||||
"d3-scale-chromatic": "^1.5.0",
|
||||
"d3-selection": "^1.4.1",
|
||||
"d3-shape": "^1.3.7",
|
||||
"d3-time-format": "^2.2.3",
|
||||
"es6-promise": "^4.2.8",
|
||||
"fibers": "^4.0.2",
|
||||
"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",
|
||||
"handlebars": "^4.7.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.15",
|
||||
"node-sass": "^4.13.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"rc-slider": "^8.6.13",
|
||||
"react": "^16.8.6",
|
||||
"react-bootstrap": "^1.0.0-beta.9",
|
||||
"rc-slider": "^8.7.1",
|
||||
"react": "^16.12.0",
|
||||
"react-bootstrap": "^1.0.0-beta.16",
|
||||
"react-contexify": "^4.1.1",
|
||||
"react-d3": "^0.4.0",
|
||||
"react-dnd": "^9.3.2",
|
||||
"react-dnd-html5-backend": "^9.3.2",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-dnd": "^9.5.1",
|
||||
"react-dnd-html5-backend": "^9.5.1",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-fullscreenable": "^2.5.1-0",
|
||||
"react-grid-system": "^4.4.10",
|
||||
"react-grid-system": "^4.4.11",
|
||||
"react-json-view": "^1.19.1",
|
||||
"react-notification-system": "^0.2.17",
|
||||
"react-rnd": "^10.0.0",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1",
|
||||
"react-scripts": "^3.0.1",
|
||||
"react-sortable-tree": "^2.6.2",
|
||||
"react-svg-pan-zoom": "^3.1.0",
|
||||
"superagent": "^5.1.0",
|
||||
"typescript": "^3.5.3",
|
||||
"react-rnd": "^10.1.4",
|
||||
"react-router": "^5.1.2",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-scripts": "^3.3.0",
|
||||
"react-sortable-tree": "^2.7.1",
|
||||
"react-svg-pan-zoom": "^3.8.0",
|
||||
"sass": "^1.24.4",
|
||||
"superagent": "^5.2.1",
|
||||
"typescript": "^3.7.4",
|
||||
"validator": "^11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
58
src/app.js
58
src/app.js
|
@ -31,7 +31,7 @@ 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 LoginStore from './user/login-store';
|
||||
import NotificationsDataManager from './common/data-managers/notifications-data-manager';
|
||||
|
||||
import Home from './common/home';
|
||||
|
@ -40,73 +40,60 @@ 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 FluxContainerConverter from "./common/FluxContainerConverter";
|
||||
|
||||
import './styles/app.css';
|
||||
|
||||
class App extends React.Component {
|
||||
|
||||
static getStores() {
|
||||
return [ SimulatorStore, UserStore, ScenarioStore];
|
||||
return [ SimulatorStore, LoginStore, ScenarioStore];
|
||||
}
|
||||
|
||||
static calculateState(prevState) {
|
||||
let currentUser = UserStore.getState().currentUser;
|
||||
|
||||
return {
|
||||
simulators: SimulatorStore.getState(),
|
||||
scenarios: ScenarioStore.getState(),
|
||||
currentRole: currentUser ? currentUser.role : '',
|
||||
currentUsername: currentUser ? currentUser.username: '',
|
||||
currentUserID: UserStore.getState().userid,
|
||||
token: UserStore.getState().token,
|
||||
currentUser: LoginStore.getState().currentUser,
|
||||
token: LoginStore.getState().token,
|
||||
|
||||
showSidebarMenu: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
componentDidMount() {
|
||||
NotificationsDataManager.setSystem(this.refs.notificationSystem);
|
||||
|
||||
// if token stored locally, request user
|
||||
const token = localStorage.getItem('token');
|
||||
const userid = localStorage.getItem('userid');
|
||||
|
||||
let token = localStorage.getItem("token");
|
||||
let currentUser = JSON.parse(localStorage.getItem("currentUser"));
|
||||
if (token != null && token !== '') {
|
||||
// save token so we dont logout
|
||||
this.setState({ token });
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/logged-in',
|
||||
token: token,
|
||||
userid: userid
|
||||
currentUser: currentUser
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// load all simulators and scenarios to fetch data
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-load',
|
||||
token: this.state.token
|
||||
});
|
||||
// AppDispatcher.dispatch({
|
||||
// type: 'simulators/start-load',
|
||||
// token: this.state.token
|
||||
// });
|
||||
//
|
||||
// AppDispatcher.dispatch({
|
||||
// type: 'scenarios/start-load',
|
||||
// token: this.state.token
|
||||
// });
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-load',
|
||||
token: this.state.token
|
||||
});
|
||||
|
||||
NotificationsDataManager.setSystem(this.refs.notificationSystem);
|
||||
}
|
||||
|
||||
showSidebarMenu = () => {
|
||||
|
@ -130,7 +117,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.currentRole} />
|
||||
<HeaderMenu onClose={this.hideSidebarMenu} currentRole={this.state.currentUser.role} />
|
||||
</Col>
|
||||
</Hidden>
|
||||
|
||||
|
@ -141,7 +128,7 @@ class App extends React.Component {
|
|||
|
||||
<div className={`app-body app-body-spacing`} >
|
||||
<Col xs={false}>
|
||||
<SidebarMenu currentRole={this.state.currentRole} />
|
||||
<SidebarMenu currentRole={this.state.currentUser.role} />
|
||||
</Col>
|
||||
|
||||
<div className={`app-content app-content-margin-left`}>
|
||||
|
@ -171,5 +158,6 @@ class App extends React.Component {
|
|||
//<Route exact path="/simulations" component={Simulations} />
|
||||
//<Route path="/simulations/:simulation" component={Simulation} />
|
||||
|
||||
export default Container.create(FluxContainerConverter.convert(App));
|
||||
let fluxContainerConverter = require('./common/FluxContainerConverter');
|
||||
export default Container.create(fluxContainerConverter.convert(App));
|
||||
//DragDropContext(HTML5Backend)(Container.create(App));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/// FluxContainerConverter.js
|
||||
/// This is an ugly workaround found here https://github.com/facebook/flux/issues/351 to make Flux Containers work with ES6
|
||||
|
||||
export default {
|
||||
module.exports = {
|
||||
convert: function(containerClass) {
|
||||
const tmp = containerClass;
|
||||
containerClass = function(...args) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ class RestAPI {
|
|||
if (token != null) {
|
||||
req.set('Authorization', "Bearer " + token);
|
||||
}
|
||||
|
||||
|
||||
req.end(function (error, res) {
|
||||
if (res == null || res.status !== 200) {
|
||||
|
||||
|
|
|
@ -68,7 +68,6 @@ 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,action.param);
|
||||
|
@ -87,17 +86,17 @@ class ArrayStore extends ReduceStore {
|
|||
|
||||
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;
|
||||
|
@ -106,7 +105,7 @@ class ArrayStore extends ReduceStore {
|
|||
return this.updateElements(state, [action.data]);
|
||||
|
||||
case this.type + '/add-error':
|
||||
|
||||
|
||||
return state;
|
||||
|
||||
|
||||
|
@ -128,30 +127,17 @@ 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;
|
||||
|
||||
case this.type + '/start-own-edit':
|
||||
case this.type + '/start-edit':
|
||||
this.dataManager.update(action.data, action.token,action.param);
|
||||
return state;
|
||||
|
||||
case this.type + '/edited':
|
||||
return this.updateElements(state, [action.data]);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -65,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':
|
||||
|
@ -76,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");
|
||||
|
|
|
@ -36,8 +36,10 @@ class EditableHeader extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ title: nextProps.title });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
title: props.title
|
||||
};
|
||||
}
|
||||
|
||||
edit = () => {
|
||||
|
|
|
@ -26,18 +26,15 @@ import React from 'react';
|
|||
//import RestAPI from '../api/rest-api';
|
||||
|
||||
import config from '../config';
|
||||
import UserStore from "../user/user-store";
|
||||
import LoginStore from "../user/login-store";
|
||||
|
||||
class Home extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let currentUser = UserStore.getState().currentUser;
|
||||
|
||||
this.state = {
|
||||
currentRole: currentUser ? currentUser.role : '',
|
||||
currentUsername: currentUser ? currentUser.username: '',
|
||||
currentUserID: currentUser ? currentUser.id: 0,
|
||||
token: UserStore.getState().token
|
||||
currentUser: LoginStore.getState().currentUser,
|
||||
token: LoginStore.getState().token
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -48,12 +45,6 @@ class Home extends React.Component {
|
|||
return '?';
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
//RestAPI.get('/api/v1/counts').then(response => {
|
||||
// this.setState({ counts: response });
|
||||
//});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="home-container">
|
||||
|
@ -64,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.currentUsername}</b> with <b>ID {this.state.currentUserID}</b> and role <b>{this.state.currentRole}</b>.
|
||||
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>.
|
||||
</p>
|
||||
{/*
|
||||
<p>
|
||||
|
|
|
@ -32,7 +32,7 @@ class CustomTable extends Component {
|
|||
this.activeInput = null;
|
||||
|
||||
this.state = {
|
||||
rows: this.getRows(props),
|
||||
rows: CustomTable.getRows(props),
|
||||
editCell: [ -1, -1 ]
|
||||
};
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ class CustomTable extends Component {
|
|||
this.setState({ editCell: [ column, row ]}); // x, y
|
||||
}
|
||||
|
||||
addCell(data, index, child) {
|
||||
static addCell(data, index, child) {
|
||||
// add data to cell
|
||||
let content = null;
|
||||
|
||||
|
@ -112,7 +112,7 @@ class CustomTable extends Component {
|
|||
}
|
||||
|
||||
if (child.props.checkbox) {
|
||||
const checkboxKey = this.props.checkboxKey;
|
||||
const checkboxKey = child.props.checkboxKey;
|
||||
|
||||
cell.push(<FormCheck className="table-control-checkbox" inline checked={checkboxKey ? data[checkboxKey] : null} onChange={e => child.props.onChecked(index, e)} />);
|
||||
}
|
||||
|
@ -122,12 +122,12 @@ class CustomTable extends Component {
|
|||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
} // addCell
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const rows = this.getRows(nextProps);
|
||||
static getDerivedStateFromProps(props, state){
|
||||
const rows = CustomTable.getRows(props);
|
||||
|
||||
this.setState({ rows });
|
||||
return { rows };
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
|
@ -147,7 +147,7 @@ class CustomTable extends Component {
|
|||
this.setState({ editCell: [ -1, -1 ] });
|
||||
}
|
||||
|
||||
getRows(props) {
|
||||
static getRows(props) {
|
||||
if (props.data == null) {
|
||||
return [];
|
||||
}
|
||||
|
@ -156,13 +156,13 @@ class CustomTable extends Component {
|
|||
// check if multiple columns
|
||||
if (Array.isArray(props.children) === false) {
|
||||
// table only has a single column
|
||||
return [ this.addCell(data, index, props.children) ];
|
||||
return [ CustomTable.addCell(data, index, props.children) ];
|
||||
}
|
||||
|
||||
const row = [];
|
||||
|
||||
for (let child of props.children) {
|
||||
row.push(this.addCell(data, index, child));
|
||||
row.push(CustomTable.addCell(data, index, child));
|
||||
}
|
||||
|
||||
return row;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import Icon from "../common/icon";
|
||||
|
||||
class DashboardButtonGroup extends React.Component {
|
||||
render() {
|
||||
|
@ -38,39 +39,39 @@ class DashboardButtonGroup extends React.Component {
|
|||
|
||||
if (this.props.editing) {
|
||||
buttons.push(
|
||||
<Button key={key++} bsStyle="info" onClick={this.props.onSave} style={buttonStyle}>
|
||||
<span class="glyphicon glyphicon-floppy-disk"></span> Save
|
||||
<Button key={key++} onClick={this.props.onSave} style={buttonStyle}>
|
||||
<Icon icon="save" /> Save
|
||||
</Button>,
|
||||
<Button key={key++} bsStyle="info" onClick={this.props.onCancel} style={buttonStyle}>
|
||||
<span class="glyphicon glyphicon-remove" ></span> Cancel
|
||||
<Button key={key++} onClick={this.props.onCancel} style={buttonStyle}>
|
||||
<Icon icon="times" /> Cancel
|
||||
</Button>
|
||||
);
|
||||
} else {
|
||||
if (this.props.fullscreen !== true) {
|
||||
buttons.push(
|
||||
<Button key={key++} bsStyle="info" onClick={this.props.onFullscreen} style={buttonStyle}>
|
||||
<span className="glyphicon glyphicon-resize-full"></span> Fullscreen
|
||||
<Button key={key++} onClick={this.props.onFullscreen} style={buttonStyle}>
|
||||
<Icon icon="expand" /> Fullscreen
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.paused) {
|
||||
buttons.push(
|
||||
<Button key={key++} bsStyle="info" onClick={this.props.onUnpause} style={buttonStyle}>
|
||||
<span className="glyphicon glyphicon-play"></span> Live
|
||||
<Button key={key++} onClick={this.props.onUnpause} style={buttonStyle}>
|
||||
<Icon icon="play" /> Live
|
||||
</Button>
|
||||
);
|
||||
} else {
|
||||
buttons.push(
|
||||
<Button key={key++} bsStyle="info" onClick={this.props.onPause} style={buttonStyle}>
|
||||
<span className="glyphicon glyphicon-pause"></span> Pause
|
||||
<Button key={key++} onClick={this.props.onPause} style={buttonStyle}>
|
||||
<Icon icon="pause" /> Pause
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
buttons.push(
|
||||
<Button key={key++} bsStyle="info" onClick={this.props.onEdit} style={buttonStyle}>
|
||||
<span className="glyphicon glyphicon-pencil"></span> Pause
|
||||
<Button key={key++} onClick={this.props.onEdit} style={buttonStyle}>
|
||||
<Icon icon="pen" /> Edit
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import React, {Component} from 'react';
|
||||
import { Container } from 'flux/utils';
|
||||
import Fullscreenable from 'react-fullscreenable';
|
||||
import classNames from 'classnames';
|
||||
|
@ -34,82 +34,139 @@ import WidgetToolbox from './widget-toolbox';
|
|||
import WidgetArea from './widget-area';
|
||||
import DashboardButtonGroup from './dashboard-button-group';
|
||||
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import DashboardStore from './dashboard-store';
|
||||
import ProjectStore from '../project/project-store';
|
||||
import SimulationStore from '../simulation/simulation-store';
|
||||
import SimulationModelStore from '../simulationmodel/simulation-model-store';
|
||||
import FileStore from '../file/file-store';
|
||||
import WidgetStore from '../widget/widget-store';
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
|
||||
import FluxContainerConverter from "../common/FluxContainerConverter";
|
||||
|
||||
import 'react-contexify/dist/ReactContexify.min.css';
|
||||
|
||||
class Dashboard extends React.Component {
|
||||
class Dashboard extends Component {
|
||||
|
||||
static lastWidgetKey = 0;
|
||||
static getStores() {
|
||||
return [ DashboardStore, ProjectStore, SimulationStore, SimulationModelStore, FileStore, UserStore ];
|
||||
return [ DashboardStore, ProjectStore, SimulationStore, SimulationModelStore, FileStore, LoginStore, WidgetStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
if (prevState == null) {
|
||||
prevState = {};
|
||||
}
|
||||
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
let maxHeight = null;
|
||||
let dashboard = Map();
|
||||
let rawDashboard = DashboardStore.getState().find(v => v._id === props.match.params.dashboard);
|
||||
let dashboards = DashboardStore.getState()
|
||||
let rawDashboard = dashboards[props.match.params.dashboard - 1];
|
||||
|
||||
if (rawDashboard != null) {
|
||||
|
||||
|
||||
if (rawDashboard) {
|
||||
dashboard = Map(rawDashboard);
|
||||
|
||||
// convert widgets list to a dictionary to be able to reference widgets
|
||||
const widgets = {};
|
||||
//let widgets = {};
|
||||
|
||||
for (let widget of dashboard.get('widgets')) {
|
||||
widgets[this.getNewWidgetKey()] = widget;
|
||||
let rawWidgets = WidgetStore.getState();
|
||||
|
||||
if(rawWidgets.length === 0){
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-load',
|
||||
token: sessionToken,
|
||||
param: '?dashboardID=1'
|
||||
});
|
||||
}
|
||||
|
||||
dashboard = dashboard.set('widgets', widgets);
|
||||
dashboard = dashboard.set('widgets', rawWidgets);
|
||||
|
||||
// this.computeHeightWithWidgets(widgets);
|
||||
/* for(let widget of dashboard.get('widgets')){
|
||||
console.log("load files got called")
|
||||
console.log(widget);
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-load',
|
||||
token: sessionToken,
|
||||
param: '?objectID=' + widget.id + '&objectType=widget'
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
// this.setState({ dashboard: selectedDashboards, project: null });
|
||||
|
||||
// AppDispatcher.dispatch({
|
||||
// type: 'projects/start-load',
|
||||
// data: selectedDashboard.get('project'),
|
||||
// token: this.state.sessionToken
|
||||
// });
|
||||
|
||||
|
||||
/* if (this.state.dashboard.has('id') === false) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-load',
|
||||
data: this.props.match.params.dashboard,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*if(Object.keys(widgets).length !== 0 ){
|
||||
this.computeHeightWithWidgets(widgets);
|
||||
}
|
||||
|
||||
let selectedDashboards = dashboard;
|
||||
|
||||
/* this.setState({ dashboard: selectedDashboards, project: null });
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'projects/start-load',
|
||||
data: selectedDashboards.get('project'),
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
let widgets = {};
|
||||
|
||||
for (let widget of dashboard.get('widgets')) {
|
||||
widgets[Dashboard.lastWidgetKey] = widget;
|
||||
Dashboard.lastWidgetKey++;
|
||||
}
|
||||
maxHeight = Object.keys(widgets).reduce( (maxHeightSoFar, widgetKey) => {
|
||||
let thisWidget = widgets[widgetKey];
|
||||
let thisWidgetHeight = thisWidget.y + thisWidget.height;
|
||||
|
||||
return thisWidgetHeight > maxHeightSoFar? thisWidgetHeight : maxHeightSoFar;
|
||||
}, 0);
|
||||
|
||||
}
|
||||
|
||||
let simulationModels = [];
|
||||
if (prevState.simulation != null) {
|
||||
simulationModels = SimulationModelStore.getState().filter(m => prevState.simulation.models.includes(m._id));
|
||||
}
|
||||
//if (prevState.simulation != null) {
|
||||
// simulationModels = SimulationModelStore.getState().filter(m => prevState.simulation.models.includes(m._id));
|
||||
//}
|
||||
|
||||
return {
|
||||
rawDashboard,
|
||||
dashboard,
|
||||
|
||||
sessionToken: UserStore.getState().token,
|
||||
projects: ProjectStore.getState(),
|
||||
simulations: SimulationStore.getState(),
|
||||
files: FileStore.getState(),
|
||||
|
||||
project: prevState.project || null,
|
||||
simulation: prevState.simulation || null,
|
||||
sessionToken: sessionToken,
|
||||
projects: null, //ProjectStore.getState(),
|
||||
simulations: null, //SimulationStore.getState(),
|
||||
files: null,
|
||||
|
||||
project: null,
|
||||
simulation: null,
|
||||
simulationModels,
|
||||
editing: prevState.editing || false,
|
||||
paused: prevState.paused || false,
|
||||
|
||||
editModal: prevState.editModal || false,
|
||||
modalData: prevState.modalData || null,
|
||||
modalIndex: prevState.modalIndex || null,
|
||||
editModal: false,
|
||||
modalData: null,
|
||||
modalIndex: null,
|
||||
widgetChangeData: [],
|
||||
widgetAddData:[],
|
||||
|
||||
maxWidgetHeight: prevState.maxWidgetHeight || 0,
|
||||
dropZoneHeight: prevState.dropZoneHeight || 0,
|
||||
maxWidgetHeight: maxHeight || null,
|
||||
dropZoneHeight: maxHeight +80 || null,
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -121,20 +178,21 @@ class Dashboard extends React.Component {
|
|||
return widgetKey;
|
||||
}
|
||||
|
||||
|
||||
//!!!won't work anymore
|
||||
componentDidMount() {
|
||||
//document.addEventListener('keydown', this.handleKeydown.bind(this));
|
||||
|
||||
if (this.state.dashboard.has('id') === false) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-load',
|
||||
data: this.props.match.params.dashboard,
|
||||
token: this.state.sessionToken
|
||||
token: this.state.sessionToken,
|
||||
param: '?scenarioID=1',
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
componentWillUnmount() {
|
||||
//document.removeEventListener('keydown', this.handleKeydown.bind(this));
|
||||
}
|
||||
|
@ -169,9 +227,9 @@ class Dashboard extends React.Component {
|
|||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
/*handleKeydown(e) {
|
||||
handleKeydown(e) {
|
||||
switch (e.key) {
|
||||
case ' ':
|
||||
case 'p':
|
||||
|
@ -185,7 +243,8 @@ class Dashboard extends React.Component {
|
|||
break;
|
||||
default:
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adapt the area's height with the position of the new widget.
|
||||
|
@ -236,17 +295,31 @@ class Dashboard extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
handleDrop = widget => {
|
||||
const widgets = this.state.dashboard.get('widgets') || [];
|
||||
handleDrop(widget) {
|
||||
widget.dashboardID = this.state.dashboard.get('id');
|
||||
console.log(widget);
|
||||
|
||||
const widgetKey = this.getNewWidgetKey();
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-add',
|
||||
token: this.state.sessionToken,
|
||||
data: widget
|
||||
});
|
||||
|
||||
let tempChanges = this.state.widgetAddData;
|
||||
tempChanges.push(widget);
|
||||
|
||||
this.setState({ widgetAddData: tempChanges})
|
||||
/*let widgets = [];
|
||||
widgets = this.state.dashboard.get('widgets');
|
||||
|
||||
const widgetKey = Dashboard.getNewWidgetKey();
|
||||
widgets[widgetKey] = widget;
|
||||
|
||||
const dashboard = this.state.dashboard.set('widgets');
|
||||
const dashboard = this.state.dashboard.set('widgets',widgets);
|
||||
|
||||
// this.increaseHeightWithWidget(widget);
|
||||
|
||||
this.setState({ dashboard });
|
||||
this.setState({ dashboard });*/
|
||||
};
|
||||
|
||||
|
||||
|
@ -255,25 +328,20 @@ class Dashboard extends React.Component {
|
|||
this.widgetChange(updated_widget, key, this.saveChanges);
|
||||
}
|
||||
|
||||
widgetChange = (widget, index, callback = null) => {
|
||||
const widgets = this.state.dashboard.get('widgets');
|
||||
widgets[index] = widget;
|
||||
widgetChange(widget, index, callback = null){
|
||||
|
||||
const dashboard = this.state.dashboard.set('widgets');
|
||||
let tempChanges = this.state.widgetChangeData;
|
||||
tempChanges.push(widget);
|
||||
|
||||
// Check if the height needs to be increased, the section may have shrunk if not
|
||||
if (!this.increaseHeightWithWidget(widget)) {
|
||||
this.computeHeightWithWidgets(dashboard.widgets);
|
||||
}
|
||||
this.setState({ widgetChangeData: tempChanges})
|
||||
|
||||
this.setState({ dashboard }, callback);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the initial height state based on the existing widgets
|
||||
*/
|
||||
computeHeightWithWidgets(widgets) {
|
||||
computeHeightWithWidgets(widgets) {
|
||||
// Compute max height from widgets
|
||||
let maxHeight = Object.keys(widgets).reduce( (maxHeightSoFar, widgetKey) => {
|
||||
let thisWidget = widgets[widgetKey];
|
||||
|
@ -289,45 +357,61 @@ class Dashboard extends React.Component {
|
|||
}
|
||||
|
||||
|
||||
editWidget = (widget, index) => {
|
||||
editWidget(widget, index){
|
||||
this.setState({ editModal: true, modalData: widget, modalIndex: index });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
closeEdit = data => {
|
||||
closeEdit(data){
|
||||
|
||||
if (data == null) {
|
||||
this.setState({ editModal: false });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const widgets = this.state.dashboard.get('widgets');
|
||||
widgets[this.state.modalIndex] = data;
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-edit',
|
||||
token: this.state.sessionToken,
|
||||
data: data
|
||||
});
|
||||
|
||||
const dashboard = this.state.dashboard.set('widgets', widgets);
|
||||
|
||||
this.setState({ editModal: false, dashboard });
|
||||
this.setState({ editModal: false });
|
||||
};
|
||||
|
||||
|
||||
deleteWidget = (widget, index) => {
|
||||
const widgets = this.state.dashboard.get('widgets');
|
||||
deleteWidget(widget, index) {
|
||||
/*const widgets = this.state.dashboard.get('widgets');
|
||||
delete widgets[index];
|
||||
|
||||
const dashboard = this.state.dashboard.set('widgets');
|
||||
|
||||
this.setState({ dashboard });
|
||||
this.setState({ dashboard });*/
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-remove',
|
||||
data: widget,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
startEditing = () => {
|
||||
startEditing(){
|
||||
this.setState({ editing: true });
|
||||
};
|
||||
|
||||
saveEditing = () => {
|
||||
saveEditing() {
|
||||
// Provide the callback so it can be called when state change is applied
|
||||
// TODO: Check if callback is needed
|
||||
this.setState({ editing: false }, this.saveChanges );
|
||||
|
||||
|
||||
this.state.widgetChangeData.forEach( widget => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-edit',
|
||||
token: this.state.sessionToken,
|
||||
data: widget
|
||||
});
|
||||
});
|
||||
this.setState({ editing: false });
|
||||
};
|
||||
|
||||
saveChanges() {
|
||||
|
@ -343,23 +427,36 @@ class Dashboard extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
cancelEditing = () => {
|
||||
this.setState({ editing: false, dasboard: {} });
|
||||
cancelEditing() {
|
||||
console.log("cancelEditing the add data: ");
|
||||
console.log(this.state.widgetAddData);
|
||||
this.state.widgetAddData.forEach( widget => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-remove',
|
||||
data: widget,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
});
|
||||
AppDispatcher.dispatch({
|
||||
type: 'widgets/start-load',
|
||||
token: this.state.sessionToken,
|
||||
param: '?dashboardID=1'
|
||||
});
|
||||
this.setState({ editing: false, widgetChangeData: [], widgetAddData: [] });
|
||||
|
||||
this.reloadDashboard();
|
||||
};
|
||||
|
||||
setGrid = value => {
|
||||
setGrid(value) {
|
||||
const dashboard = this.state.dashboard.set('grid', value);
|
||||
|
||||
this.setState({ dashboard });
|
||||
};
|
||||
|
||||
pauseData = () => {
|
||||
pauseData(){
|
||||
this.setState({ paused: true });
|
||||
};
|
||||
|
||||
unpauseData = () => {
|
||||
unpauseData() {
|
||||
this.setState({ paused: false });
|
||||
};
|
||||
|
||||
|
@ -367,9 +464,8 @@ class Dashboard extends React.Component {
|
|||
render() {
|
||||
const widgets = this.state.dashboard.get('widgets');
|
||||
const grid = this.state.dashboard.get('grid');
|
||||
|
||||
const boxClasses = classNames('section', 'box', { 'fullscreen-padding': this.props.isFullscreen });
|
||||
|
||||
let draggable = this.state.editing;
|
||||
return <div className={boxClasses} >
|
||||
<div className='section-header box-header'>
|
||||
<div className="section-title">
|
||||
|
@ -378,47 +474,86 @@ class Dashboard extends React.Component {
|
|||
|
||||
<DashboardButtonGroup
|
||||
editing={this.state.editing}
|
||||
onEdit={this.startEditing.bind(this)}
|
||||
fullscreen={this.props.isFullscreen}
|
||||
paused={this.state.paused}
|
||||
onEdit={this.startEditing}
|
||||
onSave={this.saveEditing}
|
||||
onCancel={this.cancelEditing}
|
||||
onSave={this.saveEditing.bind(this)}
|
||||
onCancel={this.cancelEditing.bind(this)}
|
||||
onFullscreen={this.props.toggleFullscreen}
|
||||
onPause={this.pauseData}
|
||||
onUnpause={this.unpauseData}
|
||||
onPause={this.pauseData.bind(this)}
|
||||
onUnpause={this.unpauseData.bind(this)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="box box-content" onContextMenu={ (e) => e.preventDefault() }>
|
||||
{this.state.editing &&
|
||||
<WidgetToolbox grid={grid} onGridChange={this.setGrid} widgets={widgets} />
|
||||
<WidgetToolbox grid={grid} onGridChange={this.setGrid.bind(this)} widgets={widgets} />
|
||||
}
|
||||
{!draggable?(
|
||||
<WidgetArea widgets={widgets} editing={this.state.editing} grid={grid} onWidgetAdded={this.handleDrop.bind(this)}>
|
||||
{widgets != null && Object.keys(widgets).map(widgetKey => (
|
||||
<WidgetContextMenu
|
||||
key={widgetKey}
|
||||
index={parseInt(widgetKey,10)}
|
||||
widget={widgets[widgetKey]}
|
||||
onEdit={this.editWidget.bind(this)}
|
||||
onDelete={this.deleteWidget.bind(this)}
|
||||
onChange={this.widgetChange.bind(this)}
|
||||
|
||||
<WidgetArea widgets={widgets} editing={this.state.editing} grid={grid} onWidgetAdded={this.handleDrop}>
|
||||
simulation={this.state.simulation}
|
||||
onWidgetChange={this.widgetChange.bind(this)}
|
||||
onWidgetStatusChange={this.widgetStatusChange.bind(this)}
|
||||
editing={this.state.editing}
|
||||
grid={grid}
|
||||
paused={this.state.paused}
|
||||
/>
|
||||
|
||||
|
||||
))}
|
||||
</WidgetArea>
|
||||
) : (
|
||||
<WidgetArea widgets={widgets} editing={this.state.editing} grid={grid} onWidgetAdded={this.handleDrop.bind(this)}>
|
||||
{widgets != null && Object.keys(widgets).map(widgetKey => (
|
||||
<Widget
|
||||
key={widgetKey}
|
||||
data={widgets[widgetKey]}
|
||||
simulation={this.state.simulation}
|
||||
onWidgetChange={(w, k) => this.widgetChange(w, k)}
|
||||
onWidgetStatusChange={(w, k) => this.widgetStatusChange(w, k)}
|
||||
onWidgetChange={this.widgetChange.bind(this)}
|
||||
onWidgetStatusChange={this.widgetStatusChange.bind(this)}
|
||||
editing={this.state.editing}
|
||||
index={widgetKey}
|
||||
index={parseInt(widgetKey,10)}
|
||||
grid={grid}
|
||||
paused={this.state.paused}
|
||||
/>
|
||||
|
||||
))}
|
||||
</WidgetArea>
|
||||
|
||||
{/* TODO: Create only one context menu for all widgets */}
|
||||
{widgets != null && Object.keys(widgets).map(widgetKey => (
|
||||
<WidgetContextMenu key={widgetKey} index={widgetKey} widget={widgets[widgetKey]} onEdit={this.editWidget} onDelete={this.deleteWidget} onChange={this.widgetChange} />
|
||||
))}
|
||||
)}
|
||||
|
||||
<EditWidget sessionToken={this.state.sessionToken} show={this.state.editModal} onClose={this.closeEdit.bind(this)} widget={this.state.modalData} simulationModels={this.state.simulationModels} files={this.state.files} />
|
||||
|
||||
|
||||
<EditWidget sessionToken={this.state.sessionToken} show={this.state.editModal} onClose={this.closeEdit} widget={this.state.modalData} simulationModels={this.state.simulationModels} files={this.state.files} />
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
/*
|
||||
onWidgetChange={(w, k) => this.widgetChange(w, k)}
|
||||
onWidgetStatusChange={(w, k) => this.widgetStatusChange(w, k)}
|
||||
|
||||
export default Fullscreenable()(Container.create(FluxContainerConverter.convert(Dashboard), { withProps: true }));
|
||||
const widgets = this.state.dashboard.get('widgets');
|
||||
widgets[index] = widget;
|
||||
|
||||
const dashboard = this.state.dashboard.set('widgets');
|
||||
|
||||
// Check if the height needs to be increased, the section may have shrunk if not
|
||||
if (!this.increaseHeightWithWidget(widget)) {
|
||||
this.computeHeightWithWidgets(dashboard.widgets);
|
||||
}
|
||||
|
||||
this.setState({ dashboard }, callback);
|
||||
*/
|
||||
|
||||
let fluxContainerConverter = require('../common/FluxContainerConverter');
|
||||
export default Fullscreenable()(Container.create(fluxContainerConverter.convert(Dashboard), { withProps: true }));
|
||||
|
|
|
@ -52,6 +52,7 @@ const dropzoneTarget = {
|
|||
};
|
||||
|
||||
function collect(connect, monitor) {
|
||||
|
||||
return {
|
||||
connectDropTarget: connect.dropTarget(),
|
||||
isOver: monitor.isOver(),
|
||||
|
@ -61,6 +62,7 @@ function collect(connect, monitor) {
|
|||
|
||||
class Dropzone extends React.Component {
|
||||
render() {
|
||||
|
||||
var toolboxClass = classNames({
|
||||
'box-content': true,
|
||||
'toolbox-dropzone': true,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -48,7 +48,7 @@ class WidgetArea extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const maxHeight = Object.values(this.props.widgets).reduce((currentHeight, widget) => {
|
||||
const maxHeight = Object.values(this.props.widgets).reduce((currentHeight, widget) => {
|
||||
const absolutHeight = widget.y + widget.height;
|
||||
|
||||
return absolutHeight > currentHeight ? absolutHeight : currentHeight;
|
||||
|
@ -67,7 +67,7 @@ WidgetArea.propTypes = {
|
|||
editing: PropTypes.bool,
|
||||
grid: PropTypes.number,
|
||||
defaultSimulationModel: PropTypes.string,
|
||||
widgets: PropTypes.object,
|
||||
//widgets: PropTypes.array,
|
||||
onWidgetAdded: PropTypes.func
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { contextMenu, Item, Separator } from 'react-contexify';
|
||||
import { Menu, Item, Separator, MenuProvider } from 'react-contexify';
|
||||
import Widget from '../widget/widget';
|
||||
|
||||
class WidgetContextMenu extends React.Component {
|
||||
editWidget = event => {
|
||||
|
@ -92,8 +93,8 @@ class WidgetContextMenu extends React.Component {
|
|||
|
||||
render() {
|
||||
const isLocked = this.props.widget.locked;
|
||||
|
||||
return <contextMenu id={'widgetMenu'+ this.props.index}>
|
||||
const ContextMenu = () => (
|
||||
<Menu id={'widgetMenu'+ this.props.index}>
|
||||
<Item disabled={isLocked} onClick={this.editWidget}>Edit</Item>
|
||||
<Item disabled={isLocked} onClick={this.deleteWidget}>Delete</Item>
|
||||
|
||||
|
@ -108,14 +109,31 @@ class WidgetContextMenu extends React.Component {
|
|||
|
||||
<Item disabled={isLocked} onClick={this.lockWidget}>Lock</Item>
|
||||
<Item disabled={isLocked === false} onClick={this.unlockWidget}>Unlock</Item>
|
||||
</contextMenu>;
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return <div>
|
||||
<MenuProvider id={'widgetMenu'+ this.props.index} style={{ border: '1px solid purple', display: 'inline-block' }}>
|
||||
<Widget
|
||||
data={this.props.widget}
|
||||
simulation={this.props.simulation}
|
||||
onWidgetChange={this.props.onWidgetChange}
|
||||
onWidgetStatusChange={this.props.onWidgetStatusChange}
|
||||
editing={this.props.editing}
|
||||
index={this.props.index}
|
||||
grid={this.props.grid}
|
||||
paused={this.props.paused}
|
||||
/>
|
||||
</MenuProvider>
|
||||
<ContextMenu />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
WidgetContextMenu.propTypes = {
|
||||
index: PropTypes.number.isRequired,
|
||||
widget: PropTypes.object.isRequired,
|
||||
onEdit: PropTypes.func,
|
||||
onEdit: PropTypes.func.isRequired,
|
||||
onDelete: PropTypes.func,
|
||||
onChange: PropTypes.func
|
||||
};
|
||||
|
|
|
@ -24,130 +24,130 @@ import { Container } from 'flux/utils';
|
|||
import { FormGroup, FormControl, FormLabel, Button, ProgressBar, Col } from 'react-bootstrap';
|
||||
|
||||
import FileStore from './file-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
|
||||
import FluxContainerConverter from "../common/FluxContainerConverter";
|
||||
|
||||
class SelectFile extends React.Component {
|
||||
static getStores() {
|
||||
return [ FileStore, UserStore ];
|
||||
static getStores() {
|
||||
return [ FileStore, LoginStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
files: FileStore.getState(),
|
||||
sessionToken: LoginStore.getState().token,
|
||||
selectedFile: '',
|
||||
uploadFile: null,
|
||||
uploadProgress: 0
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-load',
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.value === state.selectedSimulator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
files: FileStore.getState(),
|
||||
sessionToken: UserStore.getState().token,
|
||||
selectedFile: '',
|
||||
uploadFile: null,
|
||||
uploadProgress: 0
|
||||
};
|
||||
let selectedSimulator = props.value;
|
||||
if (selectedSimulator == null) {
|
||||
if (state.simulators.length > 0) {
|
||||
selectedSimulator = state.simulators[0]._id;
|
||||
} else {
|
||||
selectedSimulator = '';
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-load',
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
}
|
||||
return {selectedSimulator};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.value === this.state.selectedSimulator) {
|
||||
return;
|
||||
}
|
||||
handleChange = event => {
|
||||
this.setState({ selectedFile: event.target.value });
|
||||
|
||||
let selectedSimulator = nextProps.value;
|
||||
if (selectedSimulator == null) {
|
||||
if (this.state.simulators.length > 0) {
|
||||
selectedSimulator = this.state.simulators[0]._id;
|
||||
} else {
|
||||
selectedSimulator = '';
|
||||
}
|
||||
}
|
||||
// send file to callback
|
||||
if (this.props.onChange != null) {
|
||||
const file = this.state.files.find(f => f._id === event.target.value);
|
||||
|
||||
this.setState({ selectedSimulator });
|
||||
}
|
||||
this.props.onChange(file);
|
||||
}
|
||||
};
|
||||
|
||||
handleChange = event => {
|
||||
this.setState({ selectedFile: event.target.value });
|
||||
selectUploadFile = event => {
|
||||
this.setState({ uploadFile: event.target.files[0] });
|
||||
};
|
||||
|
||||
// send file to callback
|
||||
if (this.props.onChange != null) {
|
||||
const file = this.state.files.find(f => f._id === event.target.value);
|
||||
startFileUpload = () => {
|
||||
// upload file
|
||||
const formData = new FormData();
|
||||
formData.append(0, this.state.uploadFile);
|
||||
|
||||
this.props.onChange(file);
|
||||
}
|
||||
}
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-upload',
|
||||
data: formData,
|
||||
token: this.state.sessionToken,
|
||||
progressCallback: this.updateUploadProgress,
|
||||
finishedCallback: this.clearProgress
|
||||
});
|
||||
};
|
||||
|
||||
selectUploadFile = event => {
|
||||
this.setState({ uploadFile: event.target.files[0] });
|
||||
}
|
||||
updateUploadProgress = event => {
|
||||
this.setState({ uploadProgress: parseInt(event.percent.toFixed(), 10) });
|
||||
};
|
||||
|
||||
startFileUpload = () => {
|
||||
// upload file
|
||||
const formData = new FormData();
|
||||
formData.append(0, this.state.uploadFile);
|
||||
clearProgress = () => {
|
||||
// select uploaded file
|
||||
const selectedFile = this.state.files[this.state.files.length - 1]._id;
|
||||
this.setState({ selectedFile, uploadProgress: 0 });
|
||||
};
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-upload',
|
||||
data: formData,
|
||||
token: this.state.sessionToken,
|
||||
progressCallback: this.updateUploadProgress,
|
||||
finishedCallback: this.clearProgress
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const fileOptions = this.state.files.map(f =>
|
||||
<option key={f._id} value={f._id}>{f.name}</option>
|
||||
);
|
||||
|
||||
updateUploadProgress = event => {
|
||||
this.setState({ uploadProgress: parseInt(event.percent.toFixed(), 10) });
|
||||
}
|
||||
const progressBarStyle = {
|
||||
marginLeft: '100px',
|
||||
marginTop: '-25px'
|
||||
};
|
||||
|
||||
clearProgress = () => {
|
||||
// select uploaded file
|
||||
const selectedFile = this.state.files[this.state.files.length - 1]._id;
|
||||
this.setState({ selectedFile, uploadProgress: 0 });
|
||||
}
|
||||
return <div>
|
||||
<FormGroup>
|
||||
<Col componentClass={FormLabel} sm={3} md={2}>
|
||||
{this.props.name}
|
||||
</Col>
|
||||
|
||||
render() {
|
||||
const fileOptions = this.state.files.map(f =>
|
||||
<option key={f._id} value={f._id}>{f.name}</option>
|
||||
);
|
||||
<Col sm={9} md={10}>
|
||||
<FormControl disabled={this.props.disabled} componentClass='select' placeholder='Select file' onChange={this.handleChange}>
|
||||
{fileOptions}
|
||||
</FormControl>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
const progressBarStyle = {
|
||||
marginLeft: '100px',
|
||||
marginTop: '-25px'
|
||||
};
|
||||
<FormGroup>
|
||||
<Col sm={9} md={10} smOffset={3} mdOffset={2}>
|
||||
<FormControl disabled={this.props.disabled} type='file' onChange={this.selectUploadFile} />
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
return <div>
|
||||
<FormGroup>
|
||||
<Col componentClass={FormLabel} sm={3} md={2}>
|
||||
{this.props.name}
|
||||
</Col>
|
||||
<FormGroup>
|
||||
<Col sm={9} md={10} smOffset={3} mdOffset={2}>
|
||||
<Button disabled={this.props.disabled} bsSize='small' onClick={this.startFileUpload}>
|
||||
Upload file
|
||||
</Button>
|
||||
|
||||
<Col sm={9} md={10}>
|
||||
<FormControl disabled={this.props.disabled} componentClass='select' placeholder='Select file' onChange={this.handleChange}>
|
||||
{fileOptions}
|
||||
</FormControl>
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<Col sm={9} md={10} smOffset={3} mdOffset={2}>
|
||||
<FormControl disabled={this.props.disabled} type='file' onChange={this.selectUploadFile} />
|
||||
</Col>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<Col sm={9} md={10} smOffset={3} mdOffset={2}>
|
||||
<Button disabled={this.props.disabled} bsSize='small' onClick={this.startFileUpload}>
|
||||
Upload file
|
||||
</Button>
|
||||
|
||||
<ProgressBar striped active now={this.state.uploadProgress} label={this.state.uploadProgress + '%'} style={progressBarStyle} />
|
||||
</Col>
|
||||
</FormGroup>
|
||||
</div>;
|
||||
}
|
||||
<ProgressBar striped active now={this.state.uploadProgress} label={this.state.uploadProgress + '%'} style={progressBarStyle} />
|
||||
</Col>
|
||||
</FormGroup>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export default Container.create(FluxContainerConverter.convert(SelectFile));
|
||||
|
|
|
@ -26,7 +26,7 @@ import FileSaver from 'file-saver';
|
|||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import ProjectStore from './project-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import DashboardStore from '../dashboard/dashboard-store';
|
||||
import SimulationStore from '../simulation/simulation-store';
|
||||
|
||||
|
@ -41,14 +41,14 @@ import DeleteDialog from '../common/dialogs/delete-dialog';
|
|||
|
||||
class Dashboards extends Component {
|
||||
static getStores() {
|
||||
return [ ProjectStore, DashboardStore, UserStore, SimulationStore ];
|
||||
return [ ProjectStore, DashboardStore, LoginStore, SimulationStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
prevState = prevState || {};
|
||||
|
||||
// load project
|
||||
const sessionToken = UserStore.getState().token;
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
|
||||
let project = ProjectStore.getState().find(project => project._id === props.match.params.project);
|
||||
if (project == null) {
|
||||
|
|
|
@ -25,7 +25,7 @@ import { Button } from 'react-bootstrap';
|
|||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import ProjectStore from './project-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import SimulationStore from '../simulation/simulation-store';
|
||||
|
||||
import Icon from '../common/icon';
|
||||
|
@ -38,14 +38,14 @@ import DeleteDialog from '../common/dialogs/delete-dialog';
|
|||
|
||||
class Projects extends React.Component {
|
||||
static getStores() {
|
||||
return [ ProjectStore, SimulationStore, UserStore ];
|
||||
return [ ProjectStore, SimulationStore, LoginStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
projects: ProjectStore.getState(),
|
||||
simulations: SimulationStore.getState(),
|
||||
sessionToken: UserStore.getState().token,
|
||||
sessionToken: LoginStore.getState().token,
|
||||
|
||||
newModal: false,
|
||||
editModal: false,
|
||||
|
|
|
@ -22,42 +22,5 @@
|
|||
|
||||
import ScenariosDataManager from './scenarios-data-manager';
|
||||
import ArrayStore from '../common/array-store';
|
||||
//import UsersDataManager from "../user/users-data-manager";
|
||||
//import SimulatorDataDataManager from "../simulator/simulator-data-data-manager";
|
||||
//import AppDispatcher from "../common/app-dispatcher";
|
||||
|
||||
export default new ArrayStore('scenarios', ScenariosDataManager);
|
||||
|
||||
|
||||
// class ScenariosStore extends ReduceStore {
|
||||
// constructor() {
|
||||
// super('scenarios', ScenariosDataManager);
|
||||
// }
|
||||
//
|
||||
// getInitialState() {
|
||||
// return {
|
||||
// scenarios: [],
|
||||
//
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// reduce(state, action) {
|
||||
// switch (action.type) {
|
||||
// case 'scenarios/load-models':
|
||||
// // request simulation model data of scenario
|
||||
// ScenariosDataManager.getSimulationModels(action.token, action.scenarioID);
|
||||
//
|
||||
// return Object.assign({}, state, { token: action.token, simulationmodels: action.simulationmodels});
|
||||
//
|
||||
// case 'scenarios/load-dashboards':
|
||||
// // request dashboard data of scenario
|
||||
// ScenariosDataManager.getDashboards(action.token, action.scenarioID);
|
||||
//
|
||||
// return Object.assign({}, state, { token: action.token, dashboards: action.dashboards});
|
||||
// default:
|
||||
// return state;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// export default new ScenariosStore();
|
||||
|
|
|
@ -27,84 +27,92 @@ 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 LoginStore from '../user/login-store';
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
|
||||
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';
|
||||
|
||||
import FluxContainerConverter from "../common/FluxContainerConverter";
|
||||
|
||||
class Scenario extends React.Component {
|
||||
static getStores() {
|
||||
return [ ScenarioStore, SimulatorStore, SimulationModelStore, UserStore ];
|
||||
return [ ScenarioStore, SimulationModelStore, DashboardStore, SimulatorStore, LoginStore];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
// get selected scenario
|
||||
const sessionToken = UserStore.getState().token;
|
||||
const sessionToken = LoginStore.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 = {};
|
||||
}
|
||||
|
||||
// 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: {},
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
//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 = () => {
|
||||
|
@ -133,8 +141,8 @@ class Scenario extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
closeDeleteModal = confirmDelete => {
|
||||
this.setState({ deleteModal: false });
|
||||
closeDeleteSimulationModelModal = confirmDelete => {
|
||||
this.setState({ deleteSimulationModelModal: false });
|
||||
|
||||
if (confirmDelete === false) {
|
||||
return;
|
||||
|
@ -142,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;
|
||||
|
@ -156,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,
|
||||
|
@ -173,6 +179,44 @@ class Scenario extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
closeNewDashboardModal(data) {
|
||||
this.setState({ newDashboardModal : false });
|
||||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-add',
|
||||
data,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
closeDeleteDashboardModal(confirmDelete){
|
||||
this.setState({ deleteDashboardModal: false });
|
||||
|
||||
if (confirmDelete === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-remove',
|
||||
data: this.state.modalDashboardData,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
|
||||
closeImportDashboardModal(data) {
|
||||
this.setState({ importDashboardModal: false });
|
||||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-add',
|
||||
data,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getSimulatorName(simulatorId) {
|
||||
for (let simulator of this.state.simulators) {
|
||||
if (simulator.id === simulatorId) {
|
||||
|
@ -185,14 +229,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) {
|
||||
|
@ -251,20 +307,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>
|
||||
|
@ -283,16 +341,46 @@ 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>;
|
||||
}
|
||||
}
|
||||
|
||||
export default Container.create(FluxContainerConverter.convert(Scenario), { withProps: true });
|
||||
let fluxContainerConverter = require('../common/FluxContainerConverter');
|
||||
export default Container.create(fluxContainerConverter.convert(Scenario), { withProps: true });
|
||||
|
|
|
@ -26,7 +26,7 @@ import FileSaver from 'file-saver';
|
|||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import ScenarioStore from './scenario-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
|
||||
import Icon from '../common/icon';
|
||||
import Table from '../common/table';
|
||||
|
@ -41,13 +41,12 @@ import FluxContainerConverter from "../common/FluxContainerConverter";
|
|||
|
||||
class Scenarios extends Component {
|
||||
static getStores() {
|
||||
return [ ScenarioStore, UserStore ];
|
||||
return [ ScenarioStore, LoginStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
const scenarios = ScenarioStore.getState();
|
||||
const sessionToken = UserStore.getState().token;
|
||||
console.log(scenarios);
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
|
||||
return {
|
||||
scenarios,
|
||||
|
@ -180,8 +179,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
|
||||
|
|
|
@ -28,7 +28,7 @@ import _ from 'lodash';
|
|||
import SimulationStore from './simulation-store';
|
||||
import SimulatorStore from '../simulator/simulator-store';
|
||||
import SimulationModelStore from '../simulationmodel/simulation-model-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
|
||||
import Icon from '../common/icon';
|
||||
|
@ -41,12 +41,12 @@ import DeleteDialog from '../common/dialogs/delete-dialog';
|
|||
|
||||
class Simulation extends React.Component {
|
||||
static getStores() {
|
||||
return [ SimulationStore, SimulatorStore, SimulationModelStore, UserStore ];
|
||||
return [ SimulationStore, SimulatorStore, SimulationModelStore, LoginStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
// get selected simulation
|
||||
const sessionToken = UserStore.getState().token;
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
|
||||
let simulation = SimulationStore.getState().find(s => s._id === props.match.params.simulation);
|
||||
if (simulation == null) {
|
||||
|
|
|
@ -26,7 +26,7 @@ import FileSaver from 'file-saver';
|
|||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import SimulationStore from './simulation-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import SimulatorStore from '../simulator/simulator-store';
|
||||
import SimulationModelStore from '../simulationmodel/simulation-model-store';
|
||||
|
||||
|
@ -42,7 +42,7 @@ import DeleteDialog from '../common/dialogs/delete-dialog';
|
|||
|
||||
class Simulations extends Component {
|
||||
static getStores() {
|
||||
return [ SimulationStore, UserStore, SimulatorStore, SimulationModelStore ];
|
||||
return [ SimulationStore, LoginStore, SimulatorStore, SimulationModelStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
|
@ -50,7 +50,7 @@ class Simulations extends Component {
|
|||
const simulationModels = SimulationModelStore.getState();
|
||||
const simulators = SimulatorStore.getState();
|
||||
|
||||
const sessionToken = UserStore.getState().token;
|
||||
const sessionToken = LoginStore.getState().token;
|
||||
|
||||
return {
|
||||
simulations,
|
||||
|
|
|
@ -41,12 +41,15 @@ class SignalMapping extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.length === this.state.length && nextProps.signals === this.state.signals) {
|
||||
return;
|
||||
}
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.length === state.length && props.signals === state.signals) {
|
||||
return null
|
||||
}
|
||||
|
||||
this.setState({ length: nextProps.length, signals: nextProps.signals });
|
||||
return{
|
||||
length: props.length,
|
||||
signals: props.signals
|
||||
};
|
||||
}
|
||||
|
||||
validateLength(){
|
||||
|
|
|
@ -24,7 +24,7 @@ import { Container } from 'flux/utils';
|
|||
import { Button, Col, Form, FormLabel } from 'react-bootstrap';
|
||||
|
||||
import SimulationModelStore from './simulation-model-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
|
||||
import SelectSimulator from '../simulator/select-simulator';
|
||||
|
@ -37,7 +37,7 @@ import FluxContainerConverter from "../common/FluxContainerConverter";
|
|||
|
||||
class SimulationModel extends React.Component {
|
||||
static getStores() {
|
||||
return [ SimulationModelStore, UserStore ];
|
||||
return [ SimulationModelStore, LoginStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
@ -45,7 +45,7 @@ class SimulationModel extends React.Component {
|
|||
|
||||
return {
|
||||
simulationModel: simulationModel || {},
|
||||
sessionToken: UserStore.getState().token
|
||||
sessionToken: LoginStore.getState().token
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -40,21 +40,23 @@ class SelectSimulator extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.value === this.state.selectedSimulator) {
|
||||
return;
|
||||
}
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.value === state.selectedSimulator) {
|
||||
return null; // no change
|
||||
}
|
||||
|
||||
let selectedSimulator = nextProps.value;
|
||||
if (selectedSimulator == null) {
|
||||
if (this.state.simulators.length > 0) {
|
||||
selectedSimulator = this.state.simulators[0].id;
|
||||
} else {
|
||||
selectedSimulator = '';
|
||||
}
|
||||
let selectedSimulator = props.value;
|
||||
if (selectedSimulator == null) {
|
||||
if (state.simulators.length > 0) {
|
||||
selectedSimulator = state.simulators[0].id;
|
||||
} else {
|
||||
selectedSimulator = '';
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ selectedSimulator });
|
||||
return {
|
||||
selectedSimulator
|
||||
};
|
||||
}
|
||||
|
||||
handleChange = event => {
|
||||
|
@ -66,7 +68,7 @@ class SelectSimulator extends React.Component {
|
|||
|
||||
this.props.onChange(simulator);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const simulatorOptions = this.state.simulators.map(s =>
|
||||
|
|
|
@ -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) {
|
||||
|
@ -31,14 +31,17 @@ class SimulatorAction extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.state.selectedAction == null) {
|
||||
if (nextProps.actions != null && nextProps.actions.length > 0) {
|
||||
this.setState({ selectedAction: nextProps.actions[0] });
|
||||
}
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (state.selectedAction == null) {
|
||||
if (props.actions != null && props.actions.length > 0) {
|
||||
return{
|
||||
selectedAction: props.actions[0]
|
||||
};
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
setAction = id => {
|
||||
// search action
|
||||
for (let action of this.props.actions) {
|
||||
|
@ -46,7 +49,7 @@ class SimulatorAction extends React.Component {
|
|||
this.setState({ selectedAction: action });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const actionList = this.props.actions.map(action => (
|
||||
|
@ -56,11 +59,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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import _ from 'lodash';
|
|||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import SimulatorStore from './simulator-store';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
|
||||
import Icon from '../common/icon';
|
||||
import Table from '../common/table';
|
||||
|
@ -43,7 +43,7 @@ import FluxContainerConverter from "../common/FluxContainerConverter";
|
|||
|
||||
class Simulators extends Component {
|
||||
static getStores() {
|
||||
return [ UserStore, SimulatorStore ];
|
||||
return [ LoginStore, SimulatorStore ];
|
||||
}
|
||||
|
||||
static statePrio(state) {
|
||||
|
@ -80,8 +80,7 @@ class Simulators extends Component {
|
|||
});
|
||||
|
||||
return {
|
||||
sessionToken: UserStore.getState().token,
|
||||
sessionUserID: UserStore.getState().userid,
|
||||
sessionToken: LoginStore.getState().token,
|
||||
simulators,
|
||||
modalSimulator: {},
|
||||
deleteModal: false,
|
||||
|
@ -94,7 +93,6 @@ class Simulators extends Component {
|
|||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-load',
|
||||
token: this.state.sessionToken,
|
||||
userid: this.state.sessionUserID
|
||||
});
|
||||
|
||||
// Start timer for periodic refresh
|
||||
|
@ -114,7 +112,6 @@ class Simulators extends Component {
|
|||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-load',
|
||||
token: this.state.sessionToken,
|
||||
userid: this.state.sessionUserID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +125,6 @@ class Simulators extends Component {
|
|||
type: 'simulators/start-add',
|
||||
data,
|
||||
token: this.state.sessionToken,
|
||||
userid: this.state.sessionUserID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +144,6 @@ class Simulators extends Component {
|
|||
type: 'simulators/start-edit',
|
||||
data: simulator,
|
||||
token: this.state.sessionToken,
|
||||
userid: this.state.sessionUserID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +159,6 @@ class Simulators extends Component {
|
|||
type: 'simulators/start-remove',
|
||||
data: this.state.modalSimulator,
|
||||
token: this.state.sessionToken,
|
||||
userid: this.state.sessionUserID
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -186,7 +180,6 @@ class Simulators extends Component {
|
|||
type: 'simulators/start-add',
|
||||
data,
|
||||
token: this.state.sessionToken,
|
||||
userid: this.state.sessionUserID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +216,6 @@ class Simulators extends Component {
|
|||
simulator: this.state.simulators[index],
|
||||
data: action.data,
|
||||
token: this.state.sessionToken,
|
||||
userid: this.state.sessionUserID
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import React from 'react';
|
|||
import {FormGroup, FormControl, FormLabel, Col} from 'react-bootstrap';
|
||||
|
||||
import Dialog from '../common/dialogs/dialog';
|
||||
import UserStore from './user-store';
|
||||
//import LoginStore from './login-store';
|
||||
|
||||
|
||||
class EditOwnUserDialog extends React.Component {
|
||||
|
@ -34,17 +34,15 @@ class EditOwnUserDialog extends React.Component {
|
|||
|
||||
this.state = {
|
||||
username: '',
|
||||
mail: '',
|
||||
role: '',
|
||||
id: '',
|
||||
mail: '',
|
||||
password: '',
|
||||
oldPassword: '',
|
||||
active: '',
|
||||
confirmpassword: ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
onClose(canceled) {
|
||||
if (canceled === false) {
|
||||
|
@ -56,26 +54,22 @@ class EditOwnUserDialog extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
handleChange(e) {
|
||||
let user = UserStore.getState().currentUser;
|
||||
this.setState({ [e.target.id]: e.target.value });
|
||||
|
||||
// check all controls
|
||||
var username = true;
|
||||
var role = true;
|
||||
var mail = true;
|
||||
var pw = true;
|
||||
var active = true;
|
||||
var oldPassword = true;
|
||||
var confirmpassword = true;
|
||||
let username = true;
|
||||
let mail = true;
|
||||
let pw = true;
|
||||
let oldPassword = true;
|
||||
let confirmpassword = true;
|
||||
|
||||
if (this.state.username === '') {
|
||||
username = false;
|
||||
}
|
||||
|
||||
|
||||
if(this.state.mail === ''){
|
||||
mail = false;
|
||||
}
|
||||
|
@ -84,10 +78,6 @@ class EditOwnUserDialog extends React.Component {
|
|||
pw = false;
|
||||
}
|
||||
|
||||
if(this.state.active === ''){
|
||||
active = false;
|
||||
}
|
||||
|
||||
if(this.state.oldPassword === ''){
|
||||
oldPassword = false;
|
||||
}
|
||||
|
@ -96,23 +86,26 @@ class EditOwnUserDialog extends React.Component {
|
|||
confirmpassword = false;
|
||||
}
|
||||
|
||||
|
||||
this.setState({
|
||||
role: user.role,
|
||||
id: user.id
|
||||
});
|
||||
|
||||
// form is valid if any of the fields contain somethig
|
||||
this.valid = username || role || active || oldPassword || mail || pw || confirmpassword;
|
||||
/*this.setState({
|
||||
role: user.role,
|
||||
id: user.id,
|
||||
active: user.active
|
||||
});*/
|
||||
|
||||
// form is valid if the following condition is met
|
||||
this.valid = username || mail || (oldPassword && pw && confirmpassword);
|
||||
|
||||
}
|
||||
|
||||
resetState() {
|
||||
this.setState({
|
||||
//username: this.props.user.username,
|
||||
//mail: this.props.user.mail,
|
||||
role: this.props.user.role,
|
||||
id: this.props.user.id
|
||||
username: '',
|
||||
mail: '',
|
||||
oldPassword: '',
|
||||
confirmpassword: '',
|
||||
password: '',
|
||||
id: this.props.user.id,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -122,12 +115,12 @@ class EditOwnUserDialog extends React.Component {
|
|||
<form>
|
||||
<FormGroup as={Col} controlId="username">
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl type="text" placeholder="Enter username" value={this.state.username} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl type="text" placeholder={this.props.user.username} value={this.state.username} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
<FormGroup as={Col} controlId="mail">
|
||||
<FormLabel>E-mail</FormLabel>
|
||||
<FormControl type="text" placeholder="Enter e-mail" value={this.state.mail} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl type="text" placeholder={this.props.user.mail} value={this.state.mail} onChange={(e) => this.handleChange(e)} />
|
||||
</FormGroup>
|
||||
<FormGroup as={Col} controlId="oldPassword">
|
||||
<FormLabel>Old Password</FormLabel>
|
||||
|
|
|
@ -113,12 +113,12 @@ class EditUserDialog extends React.Component {
|
|||
<form>
|
||||
<FormGroup as={Col} controlId="username">
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl type="text" placeholder="Enter username" value={this.state.username} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl type="text" placeholder={this.props.user.username} value={this.state.username} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl.Feedback />
|
||||
</FormGroup>
|
||||
<FormGroup as={Col} controlId="mail">
|
||||
<FormLabel>E-mail</FormLabel>
|
||||
<FormControl type="text" placeholder="Enter e-mail" value={this.state.mail} onChange={(e) => this.handleChange(e)} />
|
||||
<FormControl type="text" placeholder={this.props.user.mail} value={this.state.mail} onChange={(e) => this.handleChange(e)} />
|
||||
</FormGroup>
|
||||
<FormGroup as={Col} controlId="oldPassword">
|
||||
<FormLabel>Admin Password</FormLabel>
|
||||
|
|
|
@ -25,17 +25,15 @@ import AppDispatcher from '../common/app-dispatcher';
|
|||
import UsersDataManager from './users-data-manager';
|
||||
import SimulatorDataDataManager from '../simulator/simulator-data-data-manager';
|
||||
|
||||
class UserStore extends ReduceStore {
|
||||
class LoginStore extends ReduceStore {
|
||||
constructor() {
|
||||
super(AppDispatcher);
|
||||
}
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
users: [],
|
||||
currentUser: null,
|
||||
token: null,
|
||||
userid: 0,
|
||||
loginMessage: null
|
||||
};
|
||||
}
|
||||
|
@ -49,19 +47,29 @@ class UserStore extends ReduceStore {
|
|||
case 'users/logout':
|
||||
// disconnect from all simulators
|
||||
SimulatorDataDataManager.closeAll();
|
||||
//remove token and current user from local storage
|
||||
localStorage.clear();
|
||||
|
||||
// delete user and token
|
||||
return Object.assign({}, state, { token: null, currentUser: null });
|
||||
|
||||
case 'users/logged-in':
|
||||
// // request logged-in user data
|
||||
UsersDataManager.getCurrentUser(action.token, action.userid);
|
||||
|
||||
return Object.assign({}, state, { token: action.token, userid: action.userid});
|
||||
UsersDataManager.getCurrentUser(action.token, action.currentUser.id);
|
||||
return Object.assign({}, state, { token: action.token, currentUser: action.currentUser});
|
||||
|
||||
case 'users/current-user':
|
||||
// // save logged-in user
|
||||
return Object.assign({}, state, { currentUser: action.user});
|
||||
return Object.assign({}, state, { currentUser: action.currentUser});
|
||||
|
||||
case 'users/start-edit-own-user':
|
||||
// update the current user
|
||||
UsersDataManager.updateCurrentUser(action.token, action.data);
|
||||
return Object.assign({}, state, { token: action.token, currentUser: action.data});
|
||||
|
||||
case 'users/reload-current-user':
|
||||
UsersDataManager.getCurrentUser(action.token, action.currentUser.id);
|
||||
return Object.assign({}, state, { token: action.token, currentUser: action.currentUser});
|
||||
|
||||
case 'users/current-user-error':
|
||||
// discard user token
|
||||
|
@ -81,4 +89,4 @@ class UserStore extends ReduceStore {
|
|||
}
|
||||
}
|
||||
|
||||
export default new UserStore();
|
||||
export default new LoginStore();
|
|
@ -31,21 +31,20 @@ import Footer from '../common/footer';
|
|||
import NotificationsDataManager from '../common/data-managers/notifications-data-manager';
|
||||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import UserStore from './user-store';
|
||||
import LoginStore from './login-store';
|
||||
|
||||
import FluxContainerConverter from "../common/FluxContainerConverter";
|
||||
|
||||
class Login extends Component {
|
||||
static getStores() {
|
||||
return [ UserStore ];
|
||||
return [ LoginStore ];
|
||||
}
|
||||
|
||||
static calculateState() {
|
||||
return {
|
||||
currentUser: UserStore.getState().currentUser,
|
||||
token: UserStore.getState().token,
|
||||
loginMessage: UserStore.getState().loginMessage,
|
||||
userid: UserStore.getState().userid
|
||||
currentUser: LoginStore.getState().currentUser,
|
||||
token: LoginStore.getState().token,
|
||||
loginMessage: LoginStore.getState().loginMessage,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -53,27 +52,29 @@ class Login extends Component {
|
|||
NotificationsDataManager.setSystem(this.refs.notificationSystem);
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
// if token stored locally, request user
|
||||
if (nextState.token == null) {
|
||||
const token = localStorage.getItem('token');
|
||||
const userid = localStorage.getItem('userid');
|
||||
componentDidUpdate(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot: SS): void {
|
||||
|
||||
if (token != null && token !== '' && nextState.currentUser == null) {
|
||||
// if token stored locally, request user
|
||||
if (this.state.token == null) {
|
||||
const token = localStorage.getItem('token');
|
||||
const currentUser = localStorage.getItem('currentUser');
|
||||
|
||||
if (token != null && token !== '' && this.state.currentUser == null) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/logged-in',
|
||||
token: token,
|
||||
userid: userid
|
||||
currentUser: currentUser
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// check if logged in
|
||||
if (nextState.currentUser != null) {
|
||||
if (this.state.currentUser != null) {
|
||||
// save login in local storage
|
||||
localStorage.setItem('token', nextState.token);
|
||||
localStorage.setItem('userid', nextState.userid);
|
||||
localStorage.setItem('token', this.state.token);
|
||||
localStorage.setItem('currentUser', JSON.stringify(this.state.currentUser));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
102
src/user/user.js
102
src/user/user.js
|
@ -24,75 +24,79 @@ import { Container } from 'flux/utils';
|
|||
import {Button, Col, Row} from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import UserStore from './user-store';
|
||||
import LoginStore from './login-store';
|
||||
import UsersStore from './users-store';
|
||||
|
||||
|
||||
import Icon from '../common/icon';
|
||||
import EditOwnUserDialog from './edit-own-user'
|
||||
|
||||
import FluxContainerConverter from "../common/FluxContainerConverter";
|
||||
import NotificationsDataManager from "../common/data-managers/notifications-data-manager"
|
||||
|
||||
|
||||
class User extends Component {
|
||||
static getStores() {
|
||||
return [ UserStore, UsersStore ];
|
||||
return [ LoginStore, UsersStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
//prevState = prevState || {};
|
||||
prevState = prevState || {};
|
||||
|
||||
let sessionToken = UserStore.getState().token;
|
||||
let user = UserStore.getState().currentUser;
|
||||
|
||||
|
||||
if(user === null) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/start-load',
|
||||
data: UserStore.getState().userid,
|
||||
token: sessionToken
|
||||
});
|
||||
|
||||
user = {};
|
||||
}
|
||||
|
||||
console.log("extracted user 2: " + user.username);
|
||||
let user = LoginStore.getState().currentUser;
|
||||
|
||||
return {
|
||||
user,
|
||||
|
||||
token: sessionToken,
|
||||
newModal: false,
|
||||
currentUser: user,
|
||||
token: LoginStore.getState().token,
|
||||
editModal: false,
|
||||
update: false,
|
||||
modalData: {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
closeEditModal(data) {
|
||||
|
||||
this.setState({ editModal: false });
|
||||
//this.setState({currentUser: data});
|
||||
let updatedData = {};
|
||||
|
||||
if (data) {
|
||||
if(data.password === data.confirmpassword){
|
||||
if(data){
|
||||
if (data.username !== ''){
|
||||
updatedData["id"] = data.id;
|
||||
updatedData["username"] = data.username;
|
||||
}
|
||||
if (data.mail !== ''){
|
||||
updatedData["id"] = data.id;
|
||||
updatedData["mail"] = data.mail;
|
||||
}
|
||||
if (data.password !== '' && data.oldPassword !== '' && data.password === data.confirmpassword ){
|
||||
updatedData["id"] = data.id;
|
||||
updatedData["password"] = data.password;
|
||||
updatedData["oldPassword"] = data.oldPassword;
|
||||
} else if (data.password !== '' && data.password !== data.confirmpassword) {
|
||||
const USER_UPDATE_ERROR_NOTIFICATION = {
|
||||
title: 'Update Error ',
|
||||
message: 'New password not correctly confirmed',
|
||||
level: 'error'
|
||||
};
|
||||
NotificationsDataManager.addNotification(USER_UPDATE_ERROR_NOTIFICATION);
|
||||
return
|
||||
}
|
||||
|
||||
if (updatedData !== {}) {
|
||||
let requestData = {};
|
||||
requestData["user"] = updatedData;
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/start-own-edit',
|
||||
data: data,
|
||||
type: 'users/start-edit-own-user',
|
||||
data: requestData,
|
||||
token: this.state.token
|
||||
});
|
||||
} else {
|
||||
const USER_UPDATE_WARNING_NOTIFICATION = {
|
||||
title: 'Update Warning ',
|
||||
message: 'No update requested, no input data',
|
||||
level: 'warning'
|
||||
};
|
||||
NotificationsDataManager.addNotification(USER_UPDATE_WARNING_NOTIFICATION);
|
||||
}
|
||||
|
||||
else{
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/confirm-pw-doesnt-match',
|
||||
data: data,
|
||||
token: this.state.token
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -112,24 +116,24 @@ class User extends Component {
|
|||
<form>
|
||||
<Row>
|
||||
<Col xs={3}>Username: </Col>
|
||||
<Col xs={3}> {this.state.user.username} </Col>
|
||||
<Col xs={3}> {this.state.currentUser.username} </Col>
|
||||
</Row>
|
||||
|
||||
|
||||
<Row as={Col} >
|
||||
<Col xs={3}>E-mail: </Col>
|
||||
<Col xs={3}> {this.state.user.mail} </Col>
|
||||
<Col xs={3}> {this.state.currentUser.mail} </Col>
|
||||
</Row>
|
||||
|
||||
<Row as={Col} >
|
||||
<Col xs={3}>Role: </Col>
|
||||
<Col xs={3}> {this.state.user.role} </Col>
|
||||
<Col xs={3}> {this.state.currentUser.role} </Col>
|
||||
</Row>
|
||||
|
||||
|
||||
<Button onClick={() => this.setState({ editModal: true })}><Icon icon='edit' /> Edit</Button>
|
||||
|
||||
<EditOwnUserDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} user={this.state.modalData} />
|
||||
<EditOwnUserDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} user={this.state.currentUser} />
|
||||
|
||||
</form>
|
||||
|
||||
|
@ -138,4 +142,8 @@ class User extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default Container.create(FluxContainerConverter.convert(User));
|
||||
|
||||
|
||||
|
||||
let fluxContainerConverter = require('../common/FluxContainerConverter');
|
||||
export default Container.create(fluxContainerConverter.convert(User));
|
||||
|
|
|
@ -33,8 +33,7 @@ class UsersDataManager extends RestDataManager {
|
|||
AppDispatcher.dispatch({
|
||||
type: 'users/logged-in',
|
||||
token: response.token,
|
||||
user: response.user,
|
||||
userid: response.user.id
|
||||
currentUser: response.user,
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
|
@ -48,7 +47,21 @@ class UsersDataManager extends RestDataManager {
|
|||
RestAPI.get(this.makeURL('/users/' + id), token).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/current-user',
|
||||
user: response.user
|
||||
currentUser: response.user
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/current-user-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updateCurrentUser(token, userUpdate){
|
||||
RestAPI.put(this.makeURL('/users/' + userUpdate.user.id), userUpdate, token).then( response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/current-user',
|
||||
currentUser: response.user
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
|
|
|
@ -24,7 +24,7 @@ import { Container } from 'flux/utils';
|
|||
import { Button } from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import UserStore from './user-store';
|
||||
import LoginStore from './login-store';
|
||||
import UsersStore from './users-store';
|
||||
|
||||
import Icon from '../common/icon';
|
||||
|
@ -34,17 +34,16 @@ import NewUserDialog from './new-user';
|
|||
import EditUserDialog from './edit-user';
|
||||
|
||||
import DeleteDialog from '../common/dialogs/delete-dialog';
|
||||
|
||||
import FluxContainerConverter from "../common/FluxContainerConverter";
|
||||
import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
|
||||
|
||||
class Users extends Component {
|
||||
static getStores() {
|
||||
return [ UserStore, UsersStore ];
|
||||
return [ LoginStore, UsersStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
||||
let tokenState = UserStore.getState().token;
|
||||
let tokenState = LoginStore.getState().token;
|
||||
|
||||
// If there is a token available and this method was called as a result of loading users
|
||||
if (!prevState && tokenState) {
|
||||
|
@ -95,22 +94,21 @@ class Users extends Component {
|
|||
this.setState({ editModal: false });
|
||||
|
||||
if (data) {
|
||||
if(data.password === data.confirmpassword){
|
||||
if(data.password === data.confirmpassword) {
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/start-edit',
|
||||
data: data,
|
||||
token: this.state.token
|
||||
});
|
||||
}
|
||||
|
||||
else{
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/confirm-pw-doesnt-match',
|
||||
data: data,
|
||||
token: this.state.token
|
||||
});
|
||||
}
|
||||
AppDispatcher.dispatch({
|
||||
type: 'users/start-edit',
|
||||
data: data,
|
||||
token: this.state.token
|
||||
});
|
||||
} else{
|
||||
const USER_UPDATE_ERROR_NOTIFICATION = {
|
||||
title: 'Update Error ',
|
||||
message: 'New password not correctly confirmed',
|
||||
level: 'error'
|
||||
};
|
||||
NotificationsDataManager.addNotification(USER_UPDATE_ERROR_NOTIFICATION)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,4 +152,5 @@ class Users extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default Container.create(FluxContainerConverter.convert(Users));
|
||||
let fluxContainerConverter = require('../common/FluxContainerConverter');
|
||||
export default Container.create(fluxContainerConverter.convert(Users));
|
||||
|
|
|
@ -28,19 +28,23 @@ class EditWidgetAspectControl extends React.Component {
|
|||
|
||||
this.state = {
|
||||
widget: {
|
||||
lockAspect: true
|
||||
customProperties:{
|
||||
isLocked: true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return{
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FormGroup>
|
||||
<FormCheck id="lockAspect" checked={this.state.widget.lockAspect} onChange={e => this.props.handleChange(e)}>Lock Aspect</FormCheck>
|
||||
<FormCheck id="lockAspect" checked={this.state.widget.customProperties.isLocked} onChange={e => this.props.handleChange(e)}>Lock Aspect</FormCheck>
|
||||
</FormGroup>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,17 +27,23 @@ class EditWidgetCheckboxControl extends React.Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
widget: {}
|
||||
widget: {
|
||||
customProperties:{
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return{
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <FormGroup>
|
||||
<FormCheck id={this.props.controlId} checked={this.state.widget[this.props.controlId] || ''} onChange={e => this.props.handleChange(e)}>{this.props.text}</FormCheck>
|
||||
<FormCheck id={this.props.controlId} label={this.props.controlId} checked={this.state.widget[this.props.controlId] || this.state.widget.customProperties[this.props.controlId] || ''} onChange={e => this.props.handleChange(e)}></FormCheck>
|
||||
</FormGroup>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,24 +43,26 @@ class EditWidgetColorControl extends Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
widget: {}
|
||||
widget: {
|
||||
customProperties:{}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<FormGroup bsClass="color-control">
|
||||
<FormGroup bsclass="color-control">
|
||||
<Row>
|
||||
<Col componentClass={FormLabel} style={{whiteSpace: 'nowrap' }} sm={2}>
|
||||
<Col className={FormLabel} style={{whiteSpace: 'nowrap' }} sm={3}>
|
||||
{ this.props.label }
|
||||
</Col>
|
||||
<Col sm={10} bsClass='colors-column'>
|
||||
<Col sm={10} bsclass='colors-column'>
|
||||
{
|
||||
EditWidgetColorControl.ColorPalette.map( (color, idx ) => {
|
||||
let colorStyle = {
|
||||
|
@ -69,7 +71,7 @@ class EditWidgetColorControl extends Component {
|
|||
};
|
||||
|
||||
let checkedClass = classNames({
|
||||
'checked': idx === this.state.widget[this.props.controlId]
|
||||
'checked': idx === this.state.widget[this.props.controlId] || this.state.widget.customProperties[this.props.controlId]
|
||||
});
|
||||
|
||||
return (<FormCheck type='radio' key={idx} name={this.props.controlId} style={colorStyle} className={checkedClass} value={idx} inline onChange={(e) => this.props.handleChange({target: { id: this.props.controlId, value: idx}})} />)
|
||||
|
|
|
@ -33,20 +33,24 @@ class EditWidgetColorZonesControl extends React.Component {
|
|||
|
||||
this.state = {
|
||||
widget: {
|
||||
customProperties:{
|
||||
zones: []
|
||||
}
|
||||
},
|
||||
selectedZones: []
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
addZone = () => {
|
||||
// add row
|
||||
const widget = this.state.widget;
|
||||
widget.zones.push({ strokeStyle: 'ffffff', min: 0, max: 100 });
|
||||
widget.customProperties.zones.push({ strokeStyle: 'ffffff', min: 0, max: 100 });
|
||||
|
||||
this.setState({ widget });
|
||||
|
||||
|
@ -58,7 +62,7 @@ class EditWidgetColorZonesControl extends React.Component {
|
|||
const widget = this.state.widget;
|
||||
|
||||
this.state.selectedZones.forEach(row => {
|
||||
widget.zones.splice(row, 1);
|
||||
widget.customProperties.zones.splice(row, 1);
|
||||
});
|
||||
|
||||
this.setState({ selectedZones: [], widget });
|
||||
|
@ -71,11 +75,11 @@ class EditWidgetColorZonesControl extends React.Component {
|
|||
const widget = this.state.widget;
|
||||
|
||||
if (column === 1) {
|
||||
widget.zones[row].strokeStyle = event.target.value;
|
||||
widget.customProperties.zones[row].strokeStyle = event.target.value;
|
||||
} else if (column === 2) {
|
||||
widget.zones[row].min = event.target.value;
|
||||
widget.customProperties.zones[row].min = event.target.value;
|
||||
} else if (column === 3) {
|
||||
widget.zones[row].max = event.target.value;
|
||||
widget.customProperties.zones[row].max = event.target.value;
|
||||
}
|
||||
|
||||
this.setState({ widget });
|
||||
|
@ -88,7 +92,7 @@ class EditWidgetColorZonesControl extends React.Component {
|
|||
const event = {
|
||||
target: {
|
||||
id: 'zones',
|
||||
value: widget.zones
|
||||
value: widget.customProperties.zones
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -117,15 +121,15 @@ class EditWidgetColorZonesControl extends React.Component {
|
|||
return <FormGroup>
|
||||
<FormLabel>Color zones</FormLabel>
|
||||
|
||||
<Table data={this.state.widget.zones}>
|
||||
<Table data={this.state.widget.customProperties.zones}>
|
||||
<TableColumn width="20" checkbox onChecked={this.checkedCell} />
|
||||
<TableColumn title="Color" dataKey="strokeStyle" inlineEditable onInlineChange={this.changeCell} />
|
||||
<TableColumn title="Minimum" dataKey="min" inlineEditable onInlineChange={this.changeCell} />
|
||||
<TableColumn title="Maximum" dataKey="max" inlineEditable onInlineChange={this.changeCell} />
|
||||
</Table>
|
||||
|
||||
<Button onClick={this.addZone} disabled={!this.props.widget.colorZones}><Icon icon="plus" /> Add</Button>
|
||||
<Button onClick={this.removeZones} disabled={!this.props.widget.colorZones}><Icon icon="minus" /> Remove</Button>
|
||||
<Button onClick={this.addZone} disabled={!this.props.widget.customProperties.colorZones}><Icon icon="plus" /> Add</Button>
|
||||
<Button onClick={this.removeZones} disabled={!this.props.widget.customProperties.colorZones}><Icon icon="minus" /> Remove</Button>
|
||||
</FormGroup>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,13 +38,13 @@ import EditWidgetMinMaxControl from './edit-widget-min-max-control';
|
|||
import EditWidgetHTMLContent from './edit-widget-html-content';
|
||||
import EditWidgetParametersControl from './edit-widget-parameters-control';
|
||||
|
||||
export default function createControls(widgetType = null, widget = null, sessionToken = null, files = null, validateForm, simulationModels, handleChange) {
|
||||
export default function CreateControls(widgetType = null, widget = null, sessionToken = null, files = null, validateForm, simulationModels, handleChange) {
|
||||
// Use a list to concatenate the controls according to the widget type
|
||||
var dialogControls = [];
|
||||
var DialogControls = [];
|
||||
|
||||
switch(widgetType) {
|
||||
case 'CustomAction':
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTextControl key={0} widget={widget} controlId={'name'} label={'Text'} placeholder={'Enter text'} validate={id => validateForm(id)} handleChange={e => handleChange(e)} />,
|
||||
<EditWidgetTextControl key={1} widget={widget} controlId={'icon'} label={'Icon'} placeholder={'Enter an awesome font icon name'} validate={id => validateForm(id)} handleChange={e => handleChange(e)} />,
|
||||
<EditWidgetSimulationControl key={2} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
|
@ -52,7 +52,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
)
|
||||
break;
|
||||
case 'Action':
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetSimulationControl key={0} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />
|
||||
)
|
||||
break;
|
||||
|
@ -60,7 +60,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
let valueBoundOnChange = (e) => {
|
||||
handleChange([e, {target: {id: 'signal', value: 0}}]);
|
||||
}
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTextControl key={0} widget={widget} controlId={'name'} label={'Text'} placeholder={'Enter text'} validate={id => validateForm(id)} handleChange={e => handleChange(e)} />,
|
||||
<EditWidgetSimulationControl key={1} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => valueBoundOnChange(e)} />,
|
||||
<EditWidgetSignalControl key={2} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
|
@ -72,7 +72,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
let lampBoundOnChange = (e) => {
|
||||
handleChange([e, {target: {id: 'signal', value: 0}}]);
|
||||
}
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetSimulationControl key={0} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => lampBoundOnChange(e)} />,
|
||||
<EditWidgetSignalControl key={1} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetTextControl key={2} widget={widget} controlId={'threshold'} label={'Threshold'} placeholder={'0.5'} validate={id => validateForm(id)} handleChange={e => handleChange(e)} />,
|
||||
|
@ -84,7 +84,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
let plotBoundOnChange = (e) => {
|
||||
handleChange([e, {target: {id: 'signals', value: []}}]);
|
||||
}
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTimeControl key={0} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetSimulationControl key={1} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => plotBoundOnChange(e)} />,
|
||||
<EditWidgetSignalsControl key={2} controlId={'signals'} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
|
@ -93,7 +93,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
);
|
||||
break;
|
||||
case 'Table':
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetSimulationControl key={0} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetCheckboxControl key={1} widget={widget} controlId={'showUnit'} text="Show unit" handleChange={e => handleChange(e)} />
|
||||
);
|
||||
|
@ -101,7 +101,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
case 'Image':
|
||||
// Restrict to only image file types (MIME)
|
||||
let imageControlFiles = files == null? [] : files.filter(file => file.type.includes('image'));
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditImageWidgetControl key={0} sessionToken={sessionToken} widget={widget} files={imageControlFiles} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetAspectControl key={1} widget={widget} handleChange={e => handleChange(e)} />
|
||||
);
|
||||
|
@ -110,7 +110,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
let gaugeBoundOnChange = (e) => {
|
||||
handleChange([e, {target: {id: 'signal', value: ''}}]);
|
||||
}
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTextControl key={0} widget={widget} controlId={'name'} label={'Text'} placeholder={'Enter text'} validate={id => validateForm(id)} handleChange={e => handleChange(e)} />,
|
||||
<EditWidgetSimulationControl key={1} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => gaugeBoundOnChange(e) } />,
|
||||
<EditWidgetSignalControl key={2} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
|
@ -123,7 +123,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
let plotTableBoundOnChange = (e) => {
|
||||
handleChange([e, {target: {id: 'preselectedSignals', value: []}}]);
|
||||
}
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetSimulationControl key={0} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => plotTableBoundOnChange(e)} />,
|
||||
<EditWidgetSignalsControl key={1} controlId={'preselectedSignals'} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetTextControl key={2} controlId={'ylabel'} label={'Y-Axis'} placeholder={'Enter a name for the Y-axis'} widget={widget} handleChange={(e) => handleChange(e)} />,
|
||||
|
@ -132,7 +132,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
);
|
||||
break;
|
||||
case 'Slider':
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTextControl key={0} widget={widget} controlId={'name'} label={'Text'} placeholder={'Enter text'} handleChange={e => handleChange(e)} validate={id => validateForm(id)} />,
|
||||
<EditWidgetOrientation key={1} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetSimulationControl key={2} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
|
@ -148,7 +148,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
let buttonBoundOnChange = (e) => {
|
||||
handleChange([e, {target: {id: 'signal', value: 0}}]);
|
||||
}
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTextControl key={0} widget={widget} controlId={'name'} label={'Text'} placeholder={'Enter text'} handleChange={e => handleChange(e)} validate={id => validateForm(id)} />,
|
||||
<EditWidgetSimulationControl key={1} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => buttonBoundOnChange(e)} />,
|
||||
<EditWidgetSignalControl key={2} widget={widget} controlId={'signal'} input validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />,
|
||||
|
@ -158,27 +158,27 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
);
|
||||
break;
|
||||
case 'Box':
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetColorControl key={0} widget={widget} controlId={'border_color'} label={'Border color'} validate={(id) => validateForm(id)} handleChange={(e) => handleChange(e)} />,
|
||||
<EditWidgetColorControl key={1} widget={widget} controlId={'background_color'} label={'Background color'} handleChange={e => handleChange(e)} />
|
||||
);
|
||||
break;
|
||||
case 'Label':
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTextControl key={0} widget={widget} controlId={'name'} label={'Text'} placeholder={'Enter text'} handleChange={e => handleChange(e)} validate={id => validateForm(id)} />,
|
||||
<EditWidgetTextSizeControl key={1} widget={widget} handleChange={e => handleChange(e)} />,
|
||||
<EditWidgetColorControl key={2} widget={widget} controlId={'fontColor'} label={'Text color'} handleChange={e => handleChange(e)} />
|
||||
);
|
||||
break;
|
||||
case 'HTML':
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetHTMLContent key={0} widget={widget} placeholder='HTML Code' controlId='content' handleChange={e => handleChange(e)} />
|
||||
);
|
||||
break;
|
||||
case 'Topology':
|
||||
// Restrict to only xml files (MIME)
|
||||
let topologyControlFiles = files == null? [] : files.filter( file => file.type.includes('xml'));
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditImageWidgetControl key={0} sessionToken={sessionToken} widget={widget} files={topologyControlFiles} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />
|
||||
);
|
||||
break;
|
||||
|
@ -187,7 +187,7 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
let inputBoundOnChange = (e) => {
|
||||
handleChange([e, {target: {id: 'signal', value: 0}}]);
|
||||
}
|
||||
dialogControls.push(
|
||||
DialogControls.push(
|
||||
<EditWidgetTextControl key={0} widget={widget} controlId={'name'} label={'Text'} placeholder={'Enter text'} validate={id => validateForm(id)} handleChange={e => handleChange(e)} />,
|
||||
<EditWidgetSimulationControl key={1} widget={widget} validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => inputBoundOnChange(e)} />,
|
||||
<EditWidgetSignalControl key={2} widget={widget} controlId={'signal'} input validate={(id) => validateForm(id)} simulationModels={simulationModels} handleChange={(e) => handleChange(e)} />
|
||||
|
@ -198,5 +198,5 @@ export default function createControls(widgetType = null, widget = null, session
|
|||
console.log('Non-valid widget type: ' + widgetType);
|
||||
}
|
||||
|
||||
return dialogControls;
|
||||
return DialogControls;
|
||||
}
|
||||
|
|
|
@ -36,15 +36,16 @@ class EditWidgetHTMLContent extends React.Component {
|
|||
event.stopPropagation();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <FormGroup controlId={this.props.controlId}>
|
||||
<FormLabel>HTML Content</FormLabel>
|
||||
<FormControl onKeyPress={this.handleKeyIgnore} componentClass="textarea" style={{ height: 200 }} placeholder={this.props.placeholder} value={this.state.widget[this.props.controlId] || ''} onChange={e => this.props.handleChange(e)} />
|
||||
<FormControl onKeyPress={this.handleKeyIgnore} componentClass="textarea" style={{ height: 200 }} placeholder={this.props.placeholder} value={this.state.widget[this.props.controlId] || this.state.widget.customProperties[this.props.controlId] || ''} onChange={e => this.props.handleChange(e)} />
|
||||
</FormGroup>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,15 +30,19 @@ class EditImageWidgetControl extends React.Component {
|
|||
|
||||
this.state = {
|
||||
widget: {
|
||||
customProperties:{
|
||||
file: ''
|
||||
}
|
||||
},
|
||||
fileList: null,
|
||||
progress: 0
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
startFileUpload = () => {
|
||||
|
@ -73,7 +77,7 @@ class EditImageWidgetControl extends React.Component {
|
|||
return <div>
|
||||
<FormGroup controlId="file">
|
||||
<FormLabel>Image</FormLabel>
|
||||
<FormControl componentClass="select" value={this.state.widget.file} onChange={(e) => this.props.handleChange(e)}>
|
||||
<FormControl componentClass="select" value={this.state.widget.customProperties.file} onChange={(e) => this.props.handleChange(e)}>
|
||||
{this.props.files.length === 0 ? (
|
||||
<option disabled value style={{ display: 'none' }}>No images found, please upload one first.</option>
|
||||
) : (
|
||||
|
|
|
@ -26,33 +26,34 @@ class EditWidgetMinMaxControl extends React.Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const widget = {};
|
||||
widget[props.controlID + "UseMinMax"] = false;
|
||||
widget[props.controlId + "Min"] = 0;
|
||||
widget[props.controlId + "Max"] = 100;
|
||||
|
||||
this.state = {
|
||||
widget
|
||||
};
|
||||
widget: {
|
||||
customProperties:{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return{
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <FormGroup>
|
||||
<FormLabel>{this.props.label}</FormLabel>
|
||||
<FormCheck id={this.props.controlId + "UseMinMax"} checked={this.state.widget[this.props.controlId + "UseMinMax"] || ''} onChange={e => this.props.handleChange(e)}>Enable min-max</FormCheck>
|
||||
<FormCheck id={this.props.controlId + "UseMinMax"} label= {"UseMinMax"} checked={this.state.widget.customProperties[this.props.controlId + "UseMinMax"] || ''} onChange={e => this.props.handleChange(e)}></FormCheck>
|
||||
|
||||
<Table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Min: <FormControl type="number" step="any" id={this.props.controlId + "Min"} disabled={!this.state.widget[this.props.controlId + "UseMinMax"]} placeholder="Minimum value" value={this.state.widget[this.props.controlId + 'Min']} onChange={e => this.props.handleChange(e)} />
|
||||
Min: <FormControl type="number" step="any" id={this.props.controlId + "Min"} disabled={!this.state.widget.customProperties[this.props.controlId + "UseMinMax"]} placeholder="Minimum value" value={this.state.widget.customProperties[this.props.controlId + 'Min']} onChange={e => this.props.handleChange(e)} />
|
||||
</td>
|
||||
<td>
|
||||
Max: <FormControl type="number" step="any" id={this.props.controlId + "Max"} disabled={!this.state.widget[this.props.controlId + "UseMinMax"]} placeholder="Maximum value" value={this.state.widget[this.props.controlId + 'Max']} onChange={e => this.props.handleChange(e)} />
|
||||
Max: <FormControl type="number" step="any" id={this.props.controlId + "Max"} disabled={!this.state.widget.customProperties[this.props.controlId + "UseMinMax"]} placeholder="Maximum value" value={this.state.widget.customProperties[this.props.controlId + 'Max']} onChange={e => this.props.handleChange(e)} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -27,20 +27,23 @@ class EditWidgetNumberControl extends Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
widget: {}
|
||||
widget: {
|
||||
customProperties:{}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return{
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FormGroup controlId={this.props.controlId}>
|
||||
<FormLabel>{this.props.label}</FormLabel>
|
||||
<FormControl type="number" step="any" defaultValue={this.props.defaultValue} value={this.state.widget[this.props.controlId] || 0} onChange={e => this.props.handleChange(e)} />
|
||||
<FormControl type="number" step="any" value={this.state.widget.customProperties[this.props.controlId] || 0} onChange={e => this.props.handleChange(e)} />
|
||||
</FormGroup>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,13 +29,16 @@ class EditWidgetOrientation extends Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
widget: {}
|
||||
widget: {
|
||||
customProperties:{}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
handleOrientationChange(orientation) {
|
||||
|
@ -48,7 +51,7 @@ class EditWidgetOrientation extends Component {
|
|||
return (
|
||||
<FormGroup controlId="orientation">
|
||||
<Row>
|
||||
<Col componentClass={FormLabel} sm={2}>
|
||||
<Col className={FormLabel} sm={3}>
|
||||
Orientation
|
||||
</Col>
|
||||
<Col sm={10}>
|
||||
|
@ -58,8 +61,7 @@ class EditWidgetOrientation extends Component {
|
|||
let name = WidgetSlider.OrientationTypes[type].name;
|
||||
|
||||
return (
|
||||
<FormCheck inline key={value} type='radio' name='orientation' checked={ value === this.state.widget.orientation } onChange={(e) => this.handleOrientationChange(value)}>
|
||||
{ name }
|
||||
<FormCheck inline label={name} key={value} id={value} type='radio' title='orientation' checked={ value === this.state.widget.customProperties.orientation } onChange={(e) => this.handleOrientationChange(value)}>
|
||||
</FormCheck>)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -32,9 +32,10 @@ class EditWidgetParametersControl extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
handleChange(value) {
|
||||
|
|
|
@ -33,9 +33,10 @@ class EditWidgetSignalControl extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -54,7 +55,7 @@ class EditWidgetSignalControl extends Component {
|
|||
return (
|
||||
<FormGroup controlId="signal">
|
||||
<FormLabel>Signal</FormLabel>
|
||||
<FormControl componentClass="select" placeholder="Select signal" value={this.state.widget.signal} onChange={(e) => this.props.handleChange(e)}>
|
||||
<FormControl as="select" placeholder="Select signal" value={this.state.widget.signal} onChange={(e) => this.props.handleChange(e)}>
|
||||
{
|
||||
signalsToRender.length === 0 ? (
|
||||
<option disabled value style={{ display: 'none' }}>No signals available.</option>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
**********************************************************************************/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { FormGroup, FormCheck, FormLabel, FormControl } from 'react-bootstrap';
|
||||
import { FormGroup, FormCheck, FormLabel } from 'react-bootstrap';
|
||||
|
||||
class EditWidgetSignalsControl extends Component {
|
||||
constructor(props) {
|
||||
|
@ -33,9 +33,10 @@ class EditWidgetSignalsControl extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
handleSignalChange(checked, index) {
|
||||
|
@ -68,7 +69,7 @@ class EditWidgetSignalsControl extends Component {
|
|||
<FormLabel>Signals</FormLabel>
|
||||
{
|
||||
signalsToRender.length === 0 || !this.state.widget.hasOwnProperty(this.props.controlId)? (
|
||||
<FormControl.Static>No signals available.</FormControl.Static>
|
||||
<FormLabel>No signals available</FormLabel>
|
||||
) : (
|
||||
signalsToRender.map((signal, index) => (
|
||||
<FormCheck key={index} checked={this.state.widget[this.props.controlId].indexOf(index) !== -1} onChange={(e) => this.handleSignalChange(e.target.checked, index)}>{signal.name}</FormCheck>
|
||||
|
|
|
@ -28,21 +28,25 @@ class EditWidgetSimulationControl extends Component {
|
|||
|
||||
this.state = {
|
||||
widget: {
|
||||
simulationModel: ''
|
||||
customProperties: {
|
||||
simulationModel: ''
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return{
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FormGroup controlId="simulationModel">
|
||||
<FormLabel>Simulation Model</FormLabel>
|
||||
<FormControl componentClass="select" placeholder="Select simulation model" value={this.state.widget.simulationModel || '' } onChange={(e) => this.props.handleChange(e)}>
|
||||
<FormControl as="select" placeholder="Select simulation model" value={this.state.widget.simulationModel || '' } onChange={(e) => this.props.handleChange(e)}>
|
||||
{
|
||||
this.props.simulationModels.length === 0 ? (
|
||||
<option disabled value style={{ display: 'none' }}> No simulation models available. </option>
|
||||
|
|
|
@ -31,14 +31,15 @@ class EditWidgetTextControl extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// Update state's widget with props
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return {
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<FormGroup controlId={this.props.controlId} validationState={this.props.validate ? this.props.validate(this.props.controlId) : null}>
|
||||
<FormGroup controlId={this.props.controlId} valid={this.props.validate ? this.props.validate(this.props.controlId) : null}>
|
||||
<FormLabel>{this.props.label}</FormLabel>
|
||||
<FormControl type="text" placeholder={this.props.placeholder} value={this.state.widget[this.props.controlId] || ''} onChange={e => this.props.handleChange(e)} />
|
||||
<FormControl.Feedback />
|
||||
|
|
|
@ -29,7 +29,7 @@ class EditWidgetTextSizeControl extends React.Component {
|
|||
return (
|
||||
<FormGroup controlId="textSize">
|
||||
<FormLabel>Text size</FormLabel>
|
||||
<FormControl componentClass="select" value={this.props.widget.textSize} onChange={e => this.props.handleChange(e)}>
|
||||
<FormControl as="select" value={this.props.widget.textSize} onChange={e => this.props.handleChange(e)}>
|
||||
{sizes.map((size, index) => (
|
||||
<option key={index} value={size}>{size}</option>
|
||||
))}
|
||||
|
|
|
@ -33,8 +33,10 @@ class EditWidgetTimeControl extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ widget: nextProps.widget });
|
||||
static getDerivedStateFromProps(props, state){
|
||||
return{
|
||||
widget: props.widget
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -24,10 +24,11 @@ import React from 'react';
|
|||
|
||||
import Dialog from '../common/dialogs/dialog';
|
||||
|
||||
import createControls from './edit-widget-control-creator';
|
||||
import CreateControls from './edit-widget-control-creator';
|
||||
|
||||
class EditWidgetDialog extends React.Component {
|
||||
valid = true;
|
||||
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -37,10 +38,13 @@ class EditWidgetDialog extends React.Component {
|
|||
name: '',
|
||||
simulationModel: '',
|
||||
signal: 0
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
onClose(canceled) {
|
||||
if (canceled === false) {
|
||||
if (this.valid) {
|
||||
|
@ -63,7 +67,8 @@ class EditWidgetDialog extends React.Component {
|
|||
}
|
||||
|
||||
handleChange(e) {
|
||||
if (e.constructor === Array) {
|
||||
|
||||
if (e.constructor === Array) {
|
||||
// Every property in the array will be updated
|
||||
let changes = e.reduce( (changesObject, event) => {
|
||||
changesObject[event.target.id] = event.target.value;
|
||||
|
@ -72,7 +77,9 @@ class EditWidgetDialog extends React.Component {
|
|||
}, {});
|
||||
|
||||
this.setState({ temporal: Object.assign({}, this.state.temporal, changes ) });
|
||||
} else {
|
||||
}
|
||||
|
||||
if(e.target.type !== 'text'){
|
||||
let changeObject = {};
|
||||
if (e.target.id === 'lockAspect') {
|
||||
changeObject[e.target.id] = e.target.checked;
|
||||
|
@ -92,12 +99,29 @@ class EditWidgetDialog extends React.Component {
|
|||
changeObject[e.target.id] = e.target.checked;
|
||||
} else if (e.target.type === 'number') {
|
||||
changeObject[e.target.id] = Number(e.target.value);
|
||||
} else {
|
||||
}
|
||||
|
||||
else {
|
||||
changeObject[e.target.id] = e.target.value;
|
||||
}
|
||||
|
||||
this.setState({ temporal: Object.assign({}, this.state.temporal, changeObject ) });
|
||||
}
|
||||
|
||||
let finalChange = this.state.temporal;
|
||||
|
||||
finalChange.customProperties[e.target.id] = changeObject[e.target.id];
|
||||
this.setState({ temporal: finalChange});
|
||||
}
|
||||
else{
|
||||
if(this.state.temporal[e.target.id]){
|
||||
let finalChange = this.state.temporal;
|
||||
|
||||
finalChange[e.target.id] = e.target.value;
|
||||
this.setState({ temporal: finalChange});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
resetState() {
|
||||
|
@ -114,7 +138,7 @@ class EditWidgetDialog extends React.Component {
|
|||
}
|
||||
|
||||
//this.valid = name;
|
||||
this.valid = true;
|
||||
this.valid = name;
|
||||
|
||||
// return state to control
|
||||
if (target === 'name') return name ? "success" : "error";
|
||||
|
@ -123,7 +147,7 @@ class EditWidgetDialog extends React.Component {
|
|||
render() {
|
||||
let controls = null;
|
||||
if (this.props.widget) {
|
||||
controls = createControls(
|
||||
controls = CreateControls(
|
||||
this.props.widget.type,
|
||||
this.state.temporal,
|
||||
this.props.sessionToken,
|
||||
|
|
|
@ -23,12 +23,11 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { Rnd } from 'react-rnd';
|
||||
import { contextMenu } from 'react-contexify';
|
||||
|
||||
class EditableWidgetContainer extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
||||
this.rnd = null;
|
||||
}
|
||||
|
||||
|
@ -66,7 +65,8 @@ class EditableWidgetContainer extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
resizeStop = (direction, delta, ref, event) => {
|
||||
resizeStop = (event, direction, ref,delta, position) => {
|
||||
|
||||
const widget = this.props.widget;
|
||||
|
||||
// resize depends on direction
|
||||
|
@ -90,21 +90,21 @@ class EditableWidgetContainer extends React.Component {
|
|||
const widget = this.props.widget;
|
||||
|
||||
const resizing = {
|
||||
bottom: !widget.locked,
|
||||
bottomLeft: !widget.locked,
|
||||
bottomRight: !widget.locked,
|
||||
left: !widget.locked,
|
||||
right: !widget.locked,
|
||||
top: !widget.locked,
|
||||
topLeft: !widget.locked,
|
||||
topRight: !widget.locked
|
||||
bottom: !widget.isLocked,
|
||||
bottomLeft: !widget.isLocked,
|
||||
bottomRight: !widget.isLocked,
|
||||
left: !widget.isLocked,
|
||||
right: !widget.idLocked,
|
||||
top: !widget.isLocked,
|
||||
topLeft: !widget.isLocked,
|
||||
topRight: !widget.isLocked
|
||||
};
|
||||
|
||||
const gridArray = [ this.props.grid, this.props.grid ];
|
||||
|
||||
const widgetClasses = classNames({
|
||||
'editing-widget': true,
|
||||
'locked': widget.locked
|
||||
'locked': widget.isLocked
|
||||
});
|
||||
|
||||
return <Rnd
|
||||
|
@ -112,7 +112,7 @@ class EditableWidgetContainer extends React.Component {
|
|||
default={{ x: Number(widget.x), y: Number(widget.y), width: widget.width, height: widget.height }}
|
||||
minWidth={widget.minWidth}
|
||||
minHeight={widget.minHeight}
|
||||
lockAspectRatio={Boolean(widget.lockAspect)}
|
||||
lockAspectRatio={Boolean(widget.isLocked)}
|
||||
bounds={'parent'}
|
||||
className={widgetClasses}
|
||||
onResizeStart={this.borderWasClicked}
|
||||
|
@ -121,13 +121,13 @@ class EditableWidgetContainer extends React.Component {
|
|||
onDragStop={this.dragStop}
|
||||
dragGrid={gridArray}
|
||||
resizeGrid={gridArray}
|
||||
zIndex={widget.z}
|
||||
zindex={widget.z}
|
||||
enableResizing={resizing}
|
||||
disableDragging={widget.locked}
|
||||
disableDragging={widget.isLocked}
|
||||
>
|
||||
<contextMenu id={'widgetMenu' + this.props.index}>
|
||||
|
||||
{this.props.children}
|
||||
</contextMenu>
|
||||
|
||||
</Rnd>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,13 @@ import PropTypes from 'prop-types';
|
|||
|
||||
class WidgetContainer extends React.Component {
|
||||
render() {
|
||||
|
||||
const containerStyle = {
|
||||
width: Number(this.props.widget.width),
|
||||
height: Number(this.props.widget.height),
|
||||
left: Number(this.props.widget.x),
|
||||
top: Number(this.props.widget.y),
|
||||
zIndex: Number(this.props.widget.z),
|
||||
zindex: Number(this.props.widget.z),
|
||||
position: 'absolute'
|
||||
};
|
||||
|
||||
|
|
|
@ -35,13 +35,14 @@ class WidgetFactory {
|
|||
x: position.x,
|
||||
y: position.y,
|
||||
z: position.z,
|
||||
locked: false
|
||||
locked: false,
|
||||
customProperties: {}
|
||||
};
|
||||
|
||||
// set type specific properties
|
||||
switch(type) {
|
||||
case 'CustomAction':
|
||||
widget.actions = [
|
||||
widget.customProperties.actions = [
|
||||
{
|
||||
action: 'stop'
|
||||
},
|
||||
|
@ -56,51 +57,51 @@ class WidgetFactory {
|
|||
}
|
||||
];
|
||||
widget.name = 'Action';
|
||||
widget.icon = 'star';
|
||||
widget.customProperties.icon = 'star';
|
||||
widget.width = 100;
|
||||
widget.height = 50;
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
break;
|
||||
case 'Action':
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
break;
|
||||
case 'Lamp':
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.signal = 0;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.signal = 0;
|
||||
widget.minWidth = 5;
|
||||
widget.minHeight = 5;
|
||||
widget.width = 20;
|
||||
widget.height = 20;
|
||||
widget.on_color = 6;
|
||||
widget.off_color = 8;
|
||||
widget.threshold = 0.5;
|
||||
widget.customProperties.on_color = 6;
|
||||
widget.customProperties.off_color = 8;
|
||||
widget.customProperties.threshold = 0.5;
|
||||
break;
|
||||
case 'Value':
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.signal = 0;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.signal = 0;
|
||||
widget.minWidth = 70;
|
||||
widget.minHeight = 20;
|
||||
widget.width = 120;
|
||||
widget.height = 30;
|
||||
widget.textSize = 16;
|
||||
widget.customProperties.textSize = 16;
|
||||
widget.name = 'Value';
|
||||
widget.showUnit = false;
|
||||
widget.customProperties.showUnit = false;
|
||||
break;
|
||||
case 'Plot':
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.signals = [ 0 ];
|
||||
widget.ylabel = '';
|
||||
widget.time = 60;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.signals = [ 0 ];
|
||||
widget.customProperties.ylabel = '';
|
||||
widget.customProperties.time = 60;
|
||||
widget.minWidth = 400;
|
||||
widget.minHeight = 200;
|
||||
widget.width = 400;
|
||||
widget.height = 200;
|
||||
widget.yMin = 0;
|
||||
widget.yMax = 10;
|
||||
widget.yUseMinMax = false;
|
||||
widget.customProperties.yMin = 0;
|
||||
widget.customProperties.yMax = 10;
|
||||
widget.customProperties.yUseMinMax = false;
|
||||
break;
|
||||
case 'Table':
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.minWidth = 200;
|
||||
widget.width = 300;
|
||||
widget.height = 200;
|
||||
|
@ -111,80 +112,85 @@ class WidgetFactory {
|
|||
widget.width = 100;
|
||||
widget.height = 35;
|
||||
widget.name = 'Label';
|
||||
widget.textSize = 32;
|
||||
widget.fontColor = 0;
|
||||
widget.customProperties.textSize = 32;
|
||||
widget.customProperties.fontColor = 0;
|
||||
break;
|
||||
case 'PlotTable':
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.preselectedSignals = [];
|
||||
widget.signals = []; // initialize selected signals
|
||||
widget.ylabel = '';
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.preselectedSignals = [];
|
||||
widget.customProperties.signals = []; // initialize selected signals
|
||||
widget.customProperties.ylabel = '';
|
||||
widget.minWidth = 200;
|
||||
widget.minHeight = 100;
|
||||
widget.width = 600;
|
||||
widget.height = 300;
|
||||
widget.time = 60;
|
||||
widget.yMin = 0;
|
||||
widget.yMax = 10;
|
||||
widget.yUseMinMax = false;
|
||||
widget.customProperties.time = 60;
|
||||
widget.customProperties.yMin = 0;
|
||||
widget.customProperties.yMax = 10;
|
||||
widget.customProperties.yUseMinMax = false;
|
||||
break;
|
||||
case 'Image':
|
||||
widget.minWidth = 20;
|
||||
widget.minHeight = 20;
|
||||
widget.width = 200;
|
||||
widget.height = 200;
|
||||
widget.lockAspect = true;
|
||||
widget.customProperties.lockAspect = true;
|
||||
break;
|
||||
case 'Button':
|
||||
widget.minWidth = 100;
|
||||
widget.minHeight = 50;
|
||||
widget.width = 100;
|
||||
widget.height = 100;
|
||||
widget.background_color = 1;
|
||||
widget.font_color = 0;
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.signal = 0;
|
||||
widget.customProperties.background_color = 1;
|
||||
widget.customProperties.font_color = 0;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.signal = 0;
|
||||
break;
|
||||
case 'Input':
|
||||
widget.minWidth = 200;
|
||||
widget.minHeight = 50;
|
||||
widget.width = 200;
|
||||
widget.height = 50;
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.signal = 0;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.signal = 0;
|
||||
break;
|
||||
case 'Slider':
|
||||
widget.minWidth = 380;
|
||||
widget.minHeight = 30;
|
||||
widget.width = 400;
|
||||
widget.height = 50;
|
||||
widget.orientation = WidgetSlider.OrientationTypes.HORIZONTAL.value; // Assign default orientation
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.signal = 0;
|
||||
widget.customProperties.orientation = WidgetSlider.OrientationTypes.HORIZONTAL.value; // Assign default orientation
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.signal = 0;
|
||||
widget.customProperties.rangeMin = 0;
|
||||
widget.customProperties.rangeMax = 200;
|
||||
widget.customProperties.rangeUseMinMax = true;
|
||||
widget.customProperties.showUnit = true
|
||||
|
||||
break;
|
||||
case 'Gauge':
|
||||
widget.simulationModel = defaultSimulationModel;
|
||||
widget.signal = 0;
|
||||
widget.customProperties.simulationModel = defaultSimulationModel;
|
||||
widget.customProperties.signal = 0;
|
||||
widget.minWidth = 100;
|
||||
widget.minHeight = 150;
|
||||
widget.width = 150;
|
||||
widget.height = 150;
|
||||
widget.colorZones = false;
|
||||
widget.zones = [];
|
||||
widget.valueMin = 0;
|
||||
widget.valueMax = 1;
|
||||
widget.valueUseMinMax = false;
|
||||
widget.customProperties.colorZones = false;
|
||||
widget.customProperties.zones = [];
|
||||
widget.customProperties.valueMin = 0;
|
||||
widget.customProperties.valueMax = 1;
|
||||
widget.customProperties.valueUseMinMax = false;
|
||||
break;
|
||||
case 'Box':
|
||||
widget.minWidth = 50;
|
||||
widget.minHeight = 50;
|
||||
widget.width = 100;
|
||||
widget.height = 100;
|
||||
widget.border_color = 0;
|
||||
widget.customProperties.border_color = 0;
|
||||
widget.z = 0;
|
||||
break;
|
||||
case 'HTML':
|
||||
widget.content = '<i>Hello World</i>';
|
||||
widget.customProperties.content = '<i>Hello World</i>';
|
||||
break;
|
||||
case 'Topology':
|
||||
widget.width = 600;
|
||||
|
|
|
@ -77,26 +77,26 @@ class Plot extends React.Component {
|
|||
this.removeInterval();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.time !== this.props.time) {
|
||||
componentDidUpdate(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot: SS): void {
|
||||
if (prevProps.time !== this.props.time) {
|
||||
this.createInterval();
|
||||
}
|
||||
|
||||
let labelMargin = 0;
|
||||
if (nextProps.yLabel !== '') {
|
||||
if (this.props.yLabel !== '') {
|
||||
labelMargin = 30;
|
||||
}
|
||||
|
||||
// check if data is invalid
|
||||
if (nextProps.data == null || nextProps.data.length === 0 || nextProps.data[0].length === 0) {
|
||||
if (this.props.data == null || this.props.data.length === 0 || this.props.data[0].length === 0) {
|
||||
// create empty plot axes
|
||||
const xScale = scaleTime().domain([Date.now() - nextProps.time * 1000, Date.now()]).range([0, nextProps.width - leftMargin - labelMargin - rightMargin]);
|
||||
const xScale = scaleTime().domain([Date.now() - this.props.time * 1000, Date.now()]).range([0, this.props.width - leftMargin - labelMargin - rightMargin]);
|
||||
let yScale;
|
||||
|
||||
if (nextProps.yUseMinMax) {
|
||||
yScale = scaleLinear().domain([nextProps.yMin, nextProps.yMax]).range([nextProps.height + topMargin - bottomMargin, topMargin]);
|
||||
if (this.props.yUseMinMax) {
|
||||
yScale = scaleLinear().domain([this.props.yMin, this.props.yMax]).range([this.props.height + topMargin - bottomMargin, topMargin]);
|
||||
} else {
|
||||
yScale = scaleLinear().domain([0, 10]).range([nextProps.height + topMargin - bottomMargin, topMargin]);
|
||||
yScale = scaleLinear().domain([0, 10]).range([this.props.height + topMargin - bottomMargin, topMargin]);
|
||||
}
|
||||
|
||||
const xAxis = axisBottom().scale(xScale).ticks(5).tickFormat(timeFormat("%M:%S"));
|
||||
|
@ -106,17 +106,20 @@ class Plot extends React.Component {
|
|||
return;
|
||||
}
|
||||
|
||||
// only show data in requested time
|
||||
let data = nextProps.data;
|
||||
// check if requested time frame has changed
|
||||
if(this.props.time !== prevProps.time) {
|
||||
// only show data in requested time
|
||||
let data = this.props.data;
|
||||
|
||||
const firstTimestamp = data[0][data[0].length - 1].x - (nextProps.time + 1) * 1000;
|
||||
if (data[0][0].x < firstTimestamp) {
|
||||
// only show data in range (+100 ms)
|
||||
const index = data[0].findIndex(value => value.x >= firstTimestamp - 100);
|
||||
data = data.map(values => values.slice(index));
|
||||
const firstTimestamp = data[0][data[0].length - 1].x - (this.props.time + 1) * 1000;
|
||||
if (data[0][0].x < firstTimestamp) {
|
||||
// only show data in range (+100 ms)
|
||||
const index = data[0].findIndex(value => value.x >= firstTimestamp - 100);
|
||||
data = data.map(values => values.slice(index));
|
||||
}
|
||||
|
||||
this.setState({data, labelMargin});
|
||||
}
|
||||
|
||||
this.setState({ data, labelMargin });
|
||||
}
|
||||
|
||||
createInterval() {
|
||||
|
|
4
src/widget/widget-store.js
Normal file
4
src/widget/widget-store.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import ArrayStore from '../common/array-store';
|
||||
import WidgetsDataManager from './widgets-data-manager';
|
||||
|
||||
export default new ArrayStore('widgets', WidgetsDataManager);
|
|
@ -23,7 +23,7 @@ import React from 'react';
|
|||
import { Container } from 'flux/utils';
|
||||
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import UserStore from '../user/user-store';
|
||||
import LoginStore from '../user/login-store';
|
||||
import SimulatorDataStore from '../simulator/simulator-data-store';
|
||||
import SimulationModelStore from '../simulationmodel/simulation-model-store';
|
||||
import FileStore from '../file/file-store';
|
||||
|
@ -54,10 +54,11 @@ import '../styles/widgets.css';
|
|||
|
||||
class Widget extends React.Component {
|
||||
static getStores() {
|
||||
return [ SimulatorDataStore, SimulationModelStore, FileStore, UserStore ];
|
||||
return [ SimulatorDataStore, SimulationModelStore, FileStore, LoginStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
||||
let simulatorData = {};
|
||||
|
||||
if (props.paused) {
|
||||
|
@ -75,7 +76,7 @@ class Widget extends React.Component {
|
|||
|
||||
sequence: prevState != null ? prevState.sequence + 1 : 0,
|
||||
|
||||
sessionToken: UserStore.getState().token
|
||||
sessionToken: LoginStore.getState().token
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -84,14 +85,16 @@ class Widget extends React.Component {
|
|||
return;
|
||||
}
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
/*AppDispatcher.dispatch({
|
||||
type: 'files/start-load',
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
token: this.state.sessionToken,
|
||||
param: '?objectID=1&objectType=widget'
|
||||
});*/
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulationModels/start-load',
|
||||
token: this.state.sessionToken
|
||||
token: this.state.sessionToken,
|
||||
param: '?scenarioID=1'
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -162,13 +165,13 @@ class Widget extends React.Component {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
rn
|
||||
|
||||
render() {
|
||||
const element = this.createWidget(this.props.data);
|
||||
|
||||
if (this.props.editing) {
|
||||
return <EditableWidgetContainer widget={this.props.data} grid={this.props.grid} index={this.props.index}>
|
||||
return <EditableWidgetContainer widget={this.props.data} grid={this.props.grid} index={this.props.index} onWidgetChange={this.props.onWidgetChange}>
|
||||
{element}
|
||||
</EditableWidgetContainer>;
|
||||
}
|
||||
|
|
3
src/widget/widgets-data-manager.js
Normal file
3
src/widget/widgets-data-manager.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import RestDataManager from '../common/data-managers/rest-data-manager';
|
||||
|
||||
export default new RestDataManager('widget', '/widgets');
|
|
@ -30,9 +30,9 @@ class WidgetBox extends Component {
|
|||
let colors = EditWidgetColorControl.ColorPalette;
|
||||
|
||||
let colorStyle = {
|
||||
borderColor: colors[this.props.widget.border_color],
|
||||
backgroundColor: colors[this.props.widget.background_color],
|
||||
opacity: this.props.widget.background_color_opacity
|
||||
borderColor: colors[this.props.widget.customProperties.border_color],
|
||||
backgroundColor: colors[this.props.widget.customProperties.background_color],
|
||||
opacity: this.props.widget.customProperties.background_color_opacity
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -34,20 +34,22 @@ class WidgetButton extends Component {
|
|||
}
|
||||
|
||||
onPress(e) {
|
||||
if (!this.props.widget.toggle) {
|
||||
console.log("button was pressed!");
|
||||
if (!this.props.widget.customProperties.toggle) {
|
||||
this.setState({ pressed: true });
|
||||
this.valueChanged(this.props.widget.on_value);
|
||||
this.valueChanged(this.props.widget.customProperties.on_value);
|
||||
}
|
||||
}
|
||||
|
||||
onRelease(e) {
|
||||
console.log("button was released!");
|
||||
let nextState = false;
|
||||
if (this.props.widget.toggle) {
|
||||
if (this.props.widget.customProperties.toggle) {
|
||||
nextState = !this.state.pressed;
|
||||
}
|
||||
|
||||
this.setState({ pressed: nextState });
|
||||
this.valueChanged(nextState ? this.props.widget.on_value : this.props.widget.off_value);
|
||||
this.valueChanged(nextState ? this.props.widget.customProperties.on_value : this.props.widget.customProperties.off_value);
|
||||
}
|
||||
|
||||
valueChanged(newValue) {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import Icon from '../../common/icon';
|
||||
import UserStore from '../../user/user-store';
|
||||
import LoginStore from '../../user/login-store';
|
||||
import SimulatorStore from '../../simulator/simulator-store';
|
||||
import AppDispatcher from '../../common/app-dispatcher';
|
||||
|
||||
|
@ -37,24 +37,24 @@ class WidgetCustomAction extends Component {
|
|||
}
|
||||
|
||||
static getStores() {
|
||||
return [ SimulatorStore ];
|
||||
return [ SimulatorStore, LoginStore ];
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.simulationModel === null)
|
||||
return;
|
||||
return null; //no change
|
||||
|
||||
this.setState({
|
||||
return{
|
||||
simulator: SimulatorStore.getState().find(s => s._id === props.simulationModel.simulator),
|
||||
sessionToken: UserStore.getState().token
|
||||
});
|
||||
sessionToken: LoginStore.getState().token
|
||||
};
|
||||
}
|
||||
|
||||
onClick() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'simulators/start-action',
|
||||
simulator: this.state.simulator,
|
||||
data: this.props.widget.actions,
|
||||
data: this.props.widget.customProperties.actions,
|
||||
token: this.state.sessionToken
|
||||
});
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class WidgetCustomAction extends Component {
|
|||
render() {
|
||||
return <div className="widget-custom-action full">
|
||||
<Button className="full" disabled={this.state.simulator === null} onClick={(e) => this.onClick()}>
|
||||
<Icon icon={this.props.widget.icon} /> <span dangerouslySetInnerHTML={{ __html: this.props.widget.name }} />
|
||||
<Icon icon={this.props.widget.customProperties.icon} /> <span dangerouslySetInnerHTML={{ __html: this.props.widget.name }} />
|
||||
</Button>
|
||||
</div>;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
import { Gauge } from 'gaugeJS';
|
||||
//import {update} from "immutable";
|
||||
|
||||
class WidgetGauge extends Component {
|
||||
constructor(props) {
|
||||
|
@ -33,7 +34,7 @@ class WidgetGauge extends Component {
|
|||
this.state = {
|
||||
value: 0,
|
||||
minValue: null,
|
||||
maxValue: null
|
||||
maxValue: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -47,99 +48,122 @@ class WidgetGauge extends Component {
|
|||
//this.updateLabels(this.state.minValue, this.state.maxValue);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
this.setState({ value: 0 });
|
||||
return;
|
||||
componentDidUpdate(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot: SS): void {
|
||||
if(prevState.minValue !== this.state.minValue){
|
||||
this.gauge.setMinValue(this.state.minValue);
|
||||
}
|
||||
if(prevState.maxValue !== this.state.maxValue){
|
||||
this.gauge.maxValue = this.state.maxValue
|
||||
}
|
||||
|
||||
const simulator = nextProps.simulationModel.simulator;
|
||||
// update gauge's value
|
||||
if(prevState.value !== this.state.value){
|
||||
this.gauge.set(this.state.value)
|
||||
}
|
||||
|
||||
// update labels
|
||||
if(prevState.minValue !== this.state.minValue || prevState.maxValue !== this.state.maxValue){
|
||||
this.updateLabels(this.state.minValue, this.state.maxValue)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.simulationModel == null) {
|
||||
return{value:0};
|
||||
}
|
||||
|
||||
const simulator = props.simulationModel.simulator;
|
||||
|
||||
// update value
|
||||
if (nextProps.data == null || nextProps.data[simulator] == null
|
||||
|| nextProps.data[simulator].output == null
|
||||
|| nextProps.data[simulator].output.values == null
|
||||
|| nextProps.data[simulator].output.values.length === 0
|
||||
|| nextProps.data[simulator].output.values[0].length === 0) {
|
||||
this.setState({ value: 0 });
|
||||
return;
|
||||
if (props.data == null
|
||||
|| props.data[simulator] == null
|
||||
|| props.data[simulator].output == null
|
||||
|| props.data[simulator].output.values == null
|
||||
|| props.data[simulator].output.values.length === 0
|
||||
|| props.data[simulator].output.values[0].length === 0) {
|
||||
return{value:0};
|
||||
}
|
||||
|
||||
// memorize if min or max value is updated
|
||||
let updateValue = false;
|
||||
let updateMinValue = false;
|
||||
let updateMaxValue = false;
|
||||
|
||||
// check if value has changed
|
||||
const signal = nextProps.data[simulator].output.values[nextProps.widget.signal];
|
||||
const signal = props.data[simulator].output.values[props.widget.customProperties.signal];
|
||||
// Take just 3 decimal positions
|
||||
// Note: Favor this method over Number.toFixed(n) in order to avoid a type conversion, since it returns a String
|
||||
if (signal != null) {
|
||||
const value = Math.round(signal[signal.length - 1].y * 1e3) / 1e3;
|
||||
if (this.state.value !== value && value != null) {
|
||||
this.setState({ value });
|
||||
let minValue = null;
|
||||
let maxValue = null;
|
||||
if (state.value !== value && value != null) {
|
||||
//value has changed
|
||||
updateValue = true;
|
||||
|
||||
// update min-max if needed
|
||||
let updateLabels = false;
|
||||
let minValue = this.state.minValue;
|
||||
let maxValue = this.state.maxValue;
|
||||
|
||||
minValue = state.minValue;
|
||||
maxValue = state.maxValue;
|
||||
|
||||
if (minValue == null) {
|
||||
minValue = value - 0.5;
|
||||
updateLabels = true;
|
||||
|
||||
this.setState({ minValue });
|
||||
this.gauge.setMinValue(minValue);
|
||||
updateMinValue = true;
|
||||
}
|
||||
|
||||
if (maxValue == null) {
|
||||
maxValue = value + 0.5;
|
||||
updateLabels = true;
|
||||
|
||||
this.setState({ maxValue });
|
||||
this.gauge.maxValue = maxValue;
|
||||
updateMaxValue = true;
|
||||
}
|
||||
|
||||
if (nextProps.widget.valueUseMinMax) {
|
||||
if (this.state.minValue > nextProps.widget.valueMin) {
|
||||
minValue = nextProps.widget.valueMin;
|
||||
|
||||
this.setState({ minValue });
|
||||
this.gauge.setMinValue(minValue);
|
||||
|
||||
if (props.widget.customProperties.valueUseMinMax) {
|
||||
if (state.minValue > props.widget.customProperties.valueMin) {
|
||||
minValue = props.widget.customProperties.valueMin;
|
||||
updateMinValue = true;
|
||||
updateLabels = true;
|
||||
}
|
||||
|
||||
if (this.state.maxValue < nextProps.widget.valueMax) {
|
||||
maxValue = nextProps.widget.valueMax;
|
||||
|
||||
this.setState({ maxValue });
|
||||
this.gauge.maxValue = maxValue;
|
||||
|
||||
if (state.maxValue < props.widget.customProperties.valueMax) {
|
||||
maxValue = props.widget.customProperties.valueMax;
|
||||
updateMaxValue = true;
|
||||
updateLabels = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (updateLabels === false) {
|
||||
// check if min/max changed
|
||||
if (minValue > this.gauge.minValue) {
|
||||
minValue = this.gauge.minValue;
|
||||
updateLabels = true;
|
||||
|
||||
this.setState({ minValue });
|
||||
if (minValue > state.gauge.minValue) {
|
||||
minValue = state.gauge.minValue;
|
||||
updateMinValue = true;
|
||||
}
|
||||
|
||||
if (maxValue < this.gauge.maxValue) {
|
||||
maxValue = this.gauge.maxValue;
|
||||
updateLabels = true;
|
||||
|
||||
this.setState({ maxValue });
|
||||
if (maxValue < state.gauge.maxValue) {
|
||||
maxValue = state.gauge.maxValue;
|
||||
updateMaxValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (updateLabels) {
|
||||
this.updateLabels(minValue, maxValue);
|
||||
}
|
||||
|
||||
// update gauge's value
|
||||
this.gauge.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
// prepare returned state
|
||||
let returnState = null;
|
||||
if(updateValue === true){
|
||||
returnState["value"] = value;
|
||||
}
|
||||
if(updateMinValue === true){
|
||||
returnState["minValue"] = minValue;
|
||||
}
|
||||
if(updateMaxValue === true){
|
||||
returnState["maxValue"] = maxValue;
|
||||
}
|
||||
|
||||
return returnState
|
||||
} // if there is a signal
|
||||
|
||||
|
||||
}
|
||||
|
||||
updateLabels(minValue, maxValue, force) {
|
||||
|
@ -153,7 +177,7 @@ class WidgetGauge extends Component {
|
|||
}
|
||||
|
||||
// calculate zones
|
||||
let zones = this.props.widget.colorZones ? this.props.widget.zones : null;
|
||||
let zones = this.props.widget.customProperties.colorZones ? this.props.widget.customProperties.zones : null;
|
||||
if (zones != null) {
|
||||
// adapt range 0-100 to actual min-max
|
||||
const step = (maxValue - minValue) / 100;
|
||||
|
@ -197,7 +221,7 @@ class WidgetGauge extends Component {
|
|||
let signalType = null;
|
||||
|
||||
if (this.props.simulationModel != null) {
|
||||
signalType = (this.props.simulationModel != null && this.props.simulationModel.outputLength > 0 && this.props.widget.signal < this.props.simulationModel.outputLength) ? this.props.simulationModel.outputMapping[this.props.widget.signal].type : '';
|
||||
signalType = (this.props.simulationModel != null && this.props.simulationModel.outputLength > 0 && this.props.widget.customProperties.signal < this.props.simulationModel.outputLength) ? this.props.simulationModel.outputMapping[this.props.widget.customProperties.signal].type : '';
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -23,7 +23,7 @@ import React from 'react';
|
|||
|
||||
class WidgetHTML extends React.Component {
|
||||
render() {
|
||||
return <div dangerouslySetInnerHTML={{__html: this.props.widget.content }} />
|
||||
return <div dangerouslySetInnerHTML={{__html: this.props.widget.customProperties.content }} />
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,20 +25,21 @@ import AppDispatcher from '../../common/app-dispatcher';
|
|||
import config from '../../config';
|
||||
|
||||
class WidgetImage extends React.Component {
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
||||
componentDidMount() {
|
||||
// Query the image referenced by the widget
|
||||
let widgetFile = nextProps.widget.file;
|
||||
if (widgetFile && !nextProps.files.find(file => file._id === widgetFile)) {
|
||||
let widgetFile = this.props.widget.customProperties.file;
|
||||
if (widgetFile && !this.props.files.find(file => file.id === widgetFile)) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-load',
|
||||
data: widgetFile,
|
||||
token: nextProps.token
|
||||
token: this.props.token
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const file = this.props.files.find(file => file._id === this.props.widget.file);
|
||||
const file = this.props.files.find(file => file._id === this.props.widget.customProperties.file);
|
||||
|
||||
return (
|
||||
<div className="full">
|
||||
|
|
|
@ -34,24 +34,25 @@ class WidgetInput extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
return;
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.simulationModel == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let returnState = null;
|
||||
// Update value
|
||||
if (nextProps.widget.default_value && this.state.value === undefined) {
|
||||
this.setState({
|
||||
value: nextProps.widget.default_value
|
||||
});
|
||||
if (props.widget.customProperties.default_value && this.state.value === undefined) {
|
||||
returnState["value"] = props.widget.customProperties.default_value;
|
||||
}
|
||||
|
||||
// Update unit
|
||||
if (nextProps.widget.simulationModel && nextProps.simulationModel.inputMapping && this.state.unit !== nextProps.simulationModel.inputMapping[nextProps.widget.signal].type) {
|
||||
this.setState({
|
||||
unit: nextProps.simulationModel.inputMapping[nextProps.widget.signal].type
|
||||
});
|
||||
if (props.widget.customProperties.simulationModel
|
||||
&& props.simulationModel.inputMapping
|
||||
&& state.unit !== props.simulationModel.inputMapping[props.widget.customProperties.signal].type) {
|
||||
returnState["unit"] = props.simulationModel.inputMapping[props.widget.customProperties.signal].type;
|
||||
}
|
||||
|
||||
return returnState;
|
||||
}
|
||||
|
||||
valueIsChanging(newValue) {
|
||||
|
@ -75,7 +76,7 @@ class WidgetInput extends Component {
|
|||
<div className="number-input-widget full">
|
||||
<Form componentClass="fieldset" horizontal>
|
||||
<FormGroup>
|
||||
<Col componentClass={FormLabel} xs={3}>
|
||||
<Col as={FormLabel} xs={3}>
|
||||
{this.props.widget.name}
|
||||
</Col>
|
||||
<Col xs={9}>
|
||||
|
|
|
@ -25,9 +25,9 @@ import EditWidgetColorControl from '../edit-widget-color-control';
|
|||
|
||||
class WidgetLabel extends Component {
|
||||
render() {
|
||||
const style = {
|
||||
fontSize: this.props.widget.textSize + 'px',
|
||||
color: EditWidgetColorControl.ColorPalette[this.props.widget.fontColor]
|
||||
const style = {
|
||||
fontSize: this.props.widget.customProperties.textSize + 'px',
|
||||
color: EditWidgetColorControl.ColorPalette[this.props.widget.customProperties.fontColor]
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -33,35 +33,38 @@ class WidgetLamp extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
this.setState({ value: '' });
|
||||
return;
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.simulationModel == null) {
|
||||
return{ value: ''};
|
||||
}
|
||||
|
||||
const simulator = nextProps.simulationModel.simulator;
|
||||
const simulator = props.simulationModel.simulator;
|
||||
|
||||
// update value
|
||||
if (nextProps.data == null || nextProps.data[simulator] == null || nextProps.data[simulator].output == null || nextProps.data[simulator].output.values == null) {
|
||||
this.setState({ value: '' });
|
||||
return;
|
||||
if (props.data == null
|
||||
|| props.data[simulator] == null
|
||||
|| props.data[simulator].output == null
|
||||
|| props.data[simulator].output.values == null) {
|
||||
return{value:''};
|
||||
}
|
||||
|
||||
// check if value has changed
|
||||
const signal = nextProps.data[simulator].output.values[nextProps.widget.signal];
|
||||
if (signal != null && this.state.value !== signal[signal.length - 1].y) {
|
||||
this.setState({ value: signal[signal.length - 1].y });
|
||||
const signal = props.data[simulator].output.values[props.widget.customProperties.signal];
|
||||
if (signal != null && state.value !== signal[signal.length - 1].y) {
|
||||
return { value: signal[signal.length - 1].y };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
let colors = EditWidgetColorControl.ColorPalette;
|
||||
let color;
|
||||
|
||||
if (Number(this.state.value) > Number(this.props.widget.threshold))
|
||||
color = colors[this.props.widget.on_color];
|
||||
if (Number(this.state.value) > Number(this.props.widget.customProperties.threshold))
|
||||
color = colors[this.props.widget.customProperties.on_color];
|
||||
else
|
||||
color = colors[this.props.widget.off_color];
|
||||
color = colors[this.props.widget.customProperties.off_color];
|
||||
|
||||
let style = {
|
||||
backgroundColor: color,
|
||||
|
|
|
@ -36,25 +36,25 @@ class WidgetPlotTable extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
componentDidUpdate(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot: SS): void {
|
||||
if (this.props.simulationModel == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update internal selected signals state with props (different array objects)
|
||||
if (this.props.widget.signals !== nextProps.widget.signals) {
|
||||
this.setState( {signals: nextProps.widget.signals});
|
||||
if (prevProps.widget.customProperties.signals !== this.props.widget.customProperties.signals) {
|
||||
this.setState( {signals: this.props.widget.customProperties.signals});
|
||||
}
|
||||
|
||||
// Identify if there was a change in the preselected signals
|
||||
if (JSON.stringify(nextProps.widget.preselectedSignals) !== JSON.stringify(this.props.widget.preselectedSignals) || this.state.preselectedSignals.length === 0) {
|
||||
// Update the currently selected signals by intersecting with the preselected signals
|
||||
if (JSON.stringify(prevProps.widget.customProperties.preselectedSignals) !== JSON.stringify(this.props.widget.customProperties.preselectedSignals)
|
||||
|| this.state.preselectedSignals.length === 0) {
|
||||
// Update the currently selected signals by intersecting with the preselected signalsWidget
|
||||
// Do the same with the plot values
|
||||
var intersection = this.computeIntersection(nextProps.widget.preselectedSignals, nextProps.widget.signals);
|
||||
var intersection = this.computeIntersection(this.props.widget.customProperties.preselectedSignals, this.props.widget.customProperties.signals);
|
||||
this.setState({ signals: intersection });
|
||||
|
||||
this.updatePreselectedSignalsState(nextProps);
|
||||
return;
|
||||
this.updatePreselectedSignalsState(this.props);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,13 +63,14 @@ class WidgetPlotTable extends Component {
|
|||
return preselectedSignals.filter( s => selectedSignals.includes(s));
|
||||
}
|
||||
|
||||
updatePreselectedSignalsState(nextProps) {
|
||||
updatePreselectedSignalsState(props) {
|
||||
// Create checkboxes using the signal indices from simulation model
|
||||
const preselectedSignals = nextProps.simulationModel.outputMapping.reduce(
|
||||
if(props.simulationModel.outputMapping){
|
||||
const preselectedSignals = props.simulationModel.outputMapping.reduce(
|
||||
// Loop through simulation model signals
|
||||
(accum, model_signal, signal_index) => {
|
||||
// Append them if they belong to the current selected type
|
||||
if (nextProps.widget.preselectedSignals.indexOf(signal_index) > -1) {
|
||||
if (props.widget.customProperties.preselectedSignals.indexOf(signal_index) > -1) {
|
||||
accum.push(
|
||||
{
|
||||
index: signal_index,
|
||||
|
@ -82,6 +83,7 @@ class WidgetPlotTable extends Component {
|
|||
}, []);
|
||||
|
||||
this.setState({ preselectedSignals });
|
||||
}
|
||||
}
|
||||
|
||||
updateSignalSelection(signal_index, checked) {
|
||||
|
@ -105,7 +107,7 @@ class WidgetPlotTable extends Component {
|
|||
|
||||
if (this.props.data[simulator] != null && this.props.data[simulator].output != null && this.props.data[simulator].output.values != null) {
|
||||
simulatorData = this.props.data[simulator].output.values.filter((values, index) => (
|
||||
this.props.widget.signals.findIndex(value => value === index) !== -1
|
||||
this.props.widget.customProperties.signals.findIndex(value => value === index) !== -1
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -150,14 +152,14 @@ class WidgetPlotTable extends Component {
|
|||
<div className="widget-plot">
|
||||
<Plot
|
||||
data={simulatorData}
|
||||
time={this.props.widget.time}
|
||||
time={this.props.widget.customProperties.time}
|
||||
width={this.props.widget.width - 100}
|
||||
height={this.props.widget.height - 55}
|
||||
yMin={this.props.widget.yMin}
|
||||
yMax={this.props.widget.yMax}
|
||||
yUseMinMax={this.props.widget.yUseMinMax}
|
||||
yMin={this.props.widget.customProperties.yMin}
|
||||
yMax={this.props.widget.customProperties.yMax}
|
||||
yUseMinMax={this.props.widget.customProperties.yUseMinMax}
|
||||
paused={this.props.paused}
|
||||
yLabel={this.props.widget.ylabel}
|
||||
yLabel={this.props.widget.customProperties.ylabel}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -34,24 +34,28 @@ class WidgetPlot extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
this.setState({ data: [], legend: [] });
|
||||
return;
|
||||
|
||||
static getDerivedStateFromProps(props, state){
|
||||
|
||||
if (props.simulationModel == null) {
|
||||
return{
|
||||
data: [],
|
||||
legend: [],
|
||||
};
|
||||
}
|
||||
|
||||
const simulator = nextProps.simulationModel.simulator;
|
||||
const simulator = props.simulationModel.simulator;
|
||||
|
||||
// Proceed if a simulation with models and a simulator are available
|
||||
if (simulator && nextProps.data[simulator] != null && nextProps.data[simulator] != null && nextProps.data[simulator].output != null && nextProps.data[simulator].output.values != null) {
|
||||
const chosenSignals = nextProps.widget.signals;
|
||||
if (simulator && props.data[simulator] != null && props.data[simulator] != null && props.data[simulator].output != null && props.data[simulator].output.values != null) {
|
||||
const chosenSignals = props.widget.customProperties.signals;
|
||||
|
||||
const data = nextProps.data[simulator].output.values.filter((values, index) => (
|
||||
nextProps.widget.signals.findIndex(value => value === index) !== -1
|
||||
const data = props.data[simulator].output.values.filter((values, index) => (
|
||||
props.widget.customProperties.signals.findIndex(value => value === index) !== -1
|
||||
));
|
||||
|
||||
// Query the signals that will be displayed in the legend
|
||||
const legend = nextProps.simulationModel.outputMapping.reduce( (accum, model_signal, signal_index) => {
|
||||
const legend = props.simulationModel.outputMapping.reduce( (accum, model_signal, signal_index) => {
|
||||
if (chosenSignals.includes(signal_index)) {
|
||||
accum.push({ index: signal_index, name: model_signal.name, type: model_signal.type });
|
||||
}
|
||||
|
@ -59,10 +63,17 @@ class WidgetPlot extends React.Component {
|
|||
return accum;
|
||||
}, []);
|
||||
|
||||
this.setState({ data, legend });
|
||||
return{
|
||||
data: data,
|
||||
legend: legend,
|
||||
};
|
||||
} else {
|
||||
this.setState({ data: [], legend: [] });
|
||||
return{
|
||||
data: [],
|
||||
legend: [],
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -72,12 +83,12 @@ class WidgetPlot extends React.Component {
|
|||
data={this.state.data}
|
||||
height={this.props.widget.height - 55}
|
||||
width={this.props.widget.width - 20}
|
||||
time={this.props.widget.time}
|
||||
yMin={this.props.widget.yMin}
|
||||
yMax={this.props.widget.yMax}
|
||||
yUseMinMax={this.props.widget.yUseMinMax}
|
||||
time={this.props.widget.customProperties.time}
|
||||
yMin={this.props.widget.customProperties.yMin}
|
||||
yMax={this.props.widget.customProperties.yMax}
|
||||
yUseMinMax={this.props.widget.customProperties.yUseMinMax}
|
||||
paused={this.props.paused}
|
||||
yLabel={this.props.widget.ylabel}
|
||||
yLabel={this.props.widget.customProperties.ylabel}
|
||||
/>
|
||||
</div>
|
||||
<PlotLegend signals={this.state.legend} />
|
||||
|
|
|
@ -39,32 +39,43 @@ class WidgetSlider extends Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
unit: ''
|
||||
unit: 'bla',
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
return;
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.simulationModel == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let returnState = {};
|
||||
|
||||
// Update value
|
||||
if (nextProps.widget.default_value && this.state.value === undefined) {
|
||||
this.setState({
|
||||
value: nextProps.widget.default_value,
|
||||
});
|
||||
if (props.widget.customProperties.default_value && state.value === undefined) {
|
||||
returnState["value"] = props.widget.customProperties.default_value;
|
||||
}
|
||||
|
||||
// Update unit
|
||||
if (nextProps.widget.simulationModel && nextProps.simulationModel.inputMapping && this.state.unit !== nextProps.simulationModel.inputMapping[nextProps.widget.signal].type) {
|
||||
this.setState({
|
||||
unit: nextProps.simulationModel.inputMapping[nextProps.widget.signal].type
|
||||
});
|
||||
if (props.widget.customProperties.simulationModel
|
||||
&& props.simulationModel.inputMapping &&
|
||||
state.unit !== props.simulationModel.inputMapping[props.widget.customProperties.signal].type) {
|
||||
returnState["unit"] = props.simulationModel.inputMapping[props.widget.customProperties.signal].type;
|
||||
}
|
||||
|
||||
if (returnState !== {}){
|
||||
return returnState;
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot: SS): void {
|
||||
// Check if the orientation changed, update the size if it did
|
||||
if (this.props.widget.orientation !== nextProps.widget.orientation) {
|
||||
let baseWidget = nextProps.widget;
|
||||
if (this.props.widget.customProperties.orientation !== prevProps.widget.customProperties.orientation) {
|
||||
let baseWidget = this.props.widget;
|
||||
|
||||
// Exchange dimensions and constraints
|
||||
let newWidget = Object.assign({}, baseWidget, {
|
||||
|
@ -72,12 +83,13 @@ class WidgetSlider extends Component {
|
|||
height: baseWidget.width,
|
||||
minWidth: baseWidget.minHeight,
|
||||
minHeight: baseWidget.minWidth,
|
||||
maxWidth: baseWidget.maxHeight,
|
||||
maxHeight: baseWidget.maxWidth
|
||||
maxWidth: baseWidget.customProperties.maxHeight,
|
||||
maxHeight: baseWidget.customProperties.maxWidth
|
||||
});
|
||||
|
||||
nextProps.onWidgetChange(newWidget);
|
||||
this.props.onWidgetChange(newWidget);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
valueIsChanging(newValue) {
|
||||
|
@ -94,11 +106,11 @@ class WidgetSlider extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
let isVertical = this.props.widget.orientation === WidgetSlider.OrientationTypes.VERTICAL.value;
|
||||
|
||||
let isVertical = this.props.widget.customProperties.orientation === WidgetSlider.OrientationTypes.VERTICAL.value;
|
||||
let fields = {
|
||||
name: this.props.widget.name,
|
||||
control: <Slider min={ this.props.widget.rangeMin } max={ this.props.widget.rangeMax } step={ this.props.widget.step } value={ this.state.value } disabled={ this.props.editing } vertical={ isVertical } onChange={ (v) => this.valueIsChanging(v) } onAfterChange={ (v) => this.valueChanged(v) }/>,
|
||||
control: <Slider min={ this.props.widget.customProperties.rangeMin } max={ this.props.widget.customProperties.rangeMax } step={ this.props.widget.customProperties.step } value={ this.state.value } disabled={ this.props.editing } vertical={ isVertical } onChange={ (v) => this.valueIsChanging(v) } onAfterChange={ (v) => this.valueChanged(v) }/>,
|
||||
value: <span>{ format('.3s')(Number.parseFloat(this.state.value)) }</span>,
|
||||
unit: <span className="signal-unit">{ this.state.unit }</span>
|
||||
}
|
||||
|
@ -111,7 +123,7 @@ class WidgetSlider extends Component {
|
|||
});
|
||||
|
||||
return (
|
||||
this.props.widget.orientation === WidgetSlider.OrientationTypes.HORIZONTAL.value? (
|
||||
!isVertical? (
|
||||
<div className={widgetClasses}>
|
||||
<label>{ fields.name }</label>
|
||||
<div className='slider'>{ fields.control }</div>
|
||||
|
@ -119,10 +131,7 @@ class WidgetSlider extends Component {
|
|||
</div>
|
||||
) : (
|
||||
<div className={widgetClasses}>
|
||||
<label>{ fields.name }</label>
|
||||
{ fields.control }
|
||||
{ fields.value }
|
||||
{ this.props.widget.showUnit && fields.unit }
|
||||
<Slider vertical min={ this.props.widget.customProperties.rangeMin } max={ this.props.widget.customProperties.rangeMax } step={ this.props.widget.customProperties.step } value={ this.state.value } disabled={ this.props.editing } onChange={ (v) => this.valueIsChanging(v) } onAfterChange={ (v) => this.valueChanged(v) }/>,
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
@ -130,3 +139,17 @@ class WidgetSlider extends Component {
|
|||
}
|
||||
|
||||
export default WidgetSlider;
|
||||
/*!isVertical? (
|
||||
<div className={widgetClasses}>
|
||||
<label>{ fields.name }</label>
|
||||
<div className='slider'>{ fields.control }</div>
|
||||
<span>{ fields.value }</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className={widgetClasses}>
|
||||
<label>{ fields.name }</label>
|
||||
{ fields.control }
|
||||
{ fields.value }
|
||||
{ this.props.widget.customProperties.showUnit && fields.unit }
|
||||
</div>
|
||||
)*/
|
||||
|
|
|
@ -36,45 +36,55 @@ class WidgetTable extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
this.setState({ rows: [], sequence: null });
|
||||
return;
|
||||
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.simulationModel == null) {
|
||||
return{
|
||||
rows: [],
|
||||
sequence: null,
|
||||
};
|
||||
}
|
||||
|
||||
const simulator = nextProps.simulationModel.simulator;
|
||||
const simulator = props.simulationModel.simulator;
|
||||
|
||||
// check data
|
||||
if (nextProps.data == null
|
||||
|| nextProps.data[simulator] == null
|
||||
|| nextProps.data[simulator].output == null
|
||||
|| nextProps.data[simulator].output.values.length === 0
|
||||
|| nextProps.data[simulator].output.values[0].length === 0) {
|
||||
if (props.data == null
|
||||
|| props.data[simulator] == null
|
||||
|| props.data[simulator].output == null
|
||||
|| props.data[simulator].output.values.length === 0
|
||||
|| props.data[simulator].output.values[0].length === 0) {
|
||||
|
||||
// clear values
|
||||
this.setState({ rows: [], sequence: null, showUnit: false });
|
||||
return;
|
||||
return{
|
||||
rows: [],
|
||||
sequence: null,
|
||||
showUnit: false,
|
||||
};
|
||||
}
|
||||
|
||||
// check if new data, otherwise skip
|
||||
/*if (this.state.sequence >= nextProps.data[simulator.node][simulator.simulator].sequence) {
|
||||
/*if (state.sequence >= props.data[simulator.node][simulator.simulator].sequence) {
|
||||
return;
|
||||
}*/
|
||||
|
||||
// get rows
|
||||
const rows = [];
|
||||
|
||||
nextProps.data[simulator].output.values.forEach((signal, index) => {
|
||||
if (index < nextProps.simulationModel.outputMapping.length) {
|
||||
props.data[simulator].output.values.forEach((signal, index) => {
|
||||
if (index < props.simulationModel.outputMapping.length) {
|
||||
rows.push({
|
||||
name: nextProps.simulationModel.outputMapping[index].name,
|
||||
unit: nextProps.simulationModel.outputMapping[index].type,
|
||||
name: props.simulationModel.outputMapping[index].name,
|
||||
unit: props.simulationModel.outputMapping[index].type,
|
||||
value: signal[signal.length - 1].y
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ showUnit: nextProps.showUnit, rows: rows, sequence: nextProps.data[simulator].output.sequence });
|
||||
return {
|
||||
showUnit: props.showUnit,
|
||||
rows: rows,
|
||||
sequence: props.data[simulator].output.sequence
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -83,7 +93,7 @@ class WidgetTable extends Component {
|
|||
<TableColumn key={2} title="Value" dataKey="value" modifier={format('.4s')} />
|
||||
];
|
||||
|
||||
if (this.props.widget.showUnit)
|
||||
if (this.props.widget.customProperties.showUnit)
|
||||
columns.push(<TableColumn key={3} title="Unit" dataKey="unit" />)
|
||||
|
||||
return (
|
||||
|
|
|
@ -28,12 +28,12 @@ import { cimsvg } from 'libcimsvg';
|
|||
// Do not show Pintura's grid
|
||||
const pinturaGridStyle = {
|
||||
display: 'none'
|
||||
}
|
||||
};
|
||||
|
||||
// Avoid another color in the frontend
|
||||
const pinturaBackingStyle = {
|
||||
fill: 'transparent'
|
||||
}
|
||||
};
|
||||
|
||||
// Center spinner
|
||||
const spinnerContainerStyle = {
|
||||
|
@ -42,16 +42,16 @@ const spinnerContainerStyle = {
|
|||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}
|
||||
};
|
||||
|
||||
// Topology failed message
|
||||
const msgContainerStyle = Object.assign({
|
||||
backgroundColor: '#ececec'
|
||||
},spinnerContainerStyle)
|
||||
},spinnerContainerStyle);
|
||||
|
||||
const msgStyle = {
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize functions
|
||||
function attachComponentEvents() {
|
||||
|
@ -105,10 +105,12 @@ class WidgetTopology extends React.Component {
|
|||
detachComponentEvents();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const file = nextProps.files.find(file => file._id === nextProps.widget.file);
|
||||
componentDidUpdate(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot: SS): void {
|
||||
const file = this.props.files.find(file => file._id === this.props.widget.customProperties.file);
|
||||
// Ensure model is requested only once or a different was selected
|
||||
if (this.props.widget.file !== nextProps.widget.file || (this.state.dashboardState === 'initial' && file)) {
|
||||
if (prevProps.widget.customProperties.file !== this.props.widget.customProperties.file
|
||||
|| (prevState.dashboardState === 'initial' && file)) {
|
||||
|
||||
this.setState({'dashboardState': 'loading' });
|
||||
if (file) {
|
||||
fetch(new Request('/' + config.publicPathBase + file.path))
|
||||
|
@ -141,7 +143,7 @@ class WidgetTopology extends React.Component {
|
|||
}
|
||||
} else {
|
||||
// No file has been selected
|
||||
if (!nextProps.widget.file) {
|
||||
if (!this.props.widget.customProperties.file) {
|
||||
this.setState({
|
||||
'dashboardState': 'show_message',
|
||||
'message': 'Select a topology model first.'});
|
||||
|
|
|
@ -32,37 +32,41 @@ class WidgetValue extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.simulationModel == null) {
|
||||
this.setState({ value: '' });
|
||||
return;
|
||||
static getDerivedStateFromProps(props, state){
|
||||
if (props.simulationModel == null) {
|
||||
return{ value: '' };
|
||||
}
|
||||
|
||||
const simulator = nextProps.simulationModel.simulator;
|
||||
const simulator = props.simulationModel.simulator;
|
||||
|
||||
// update value
|
||||
if (nextProps.data == null || nextProps.data[simulator] == null || nextProps.data[simulator].output == null || nextProps.data[simulator].output.values == null) {
|
||||
this.setState({ value: '' });
|
||||
return;
|
||||
if (props.data == null || props.data[simulator] == null || props.data[simulator].output == null || props.data[simulator].output.values == null) {
|
||||
return{ value: '' };
|
||||
}
|
||||
|
||||
const unit = nextProps.simulationModel.outputMapping[nextProps.widget.signal].type;
|
||||
// TODO fixme (unit)
|
||||
//const unit = props.simulationModel.outputMapping[props.widget.customProperties.signal].type;
|
||||
const unit = 42;
|
||||
|
||||
// check if value has changed
|
||||
const signal = nextProps.data[simulator].output.values[nextProps.widget.signal];
|
||||
if (signal != null && this.state.value !== signal[signal.length - 1].y) {
|
||||
this.setState({ value: signal[signal.length - 1].y, unit });
|
||||
const signal = props.data[simulator].output.values[props.widget.customProperties.signal];
|
||||
if (signal != null && state.value !== signal[signal.length - 1].y) {
|
||||
return {
|
||||
value: signal[signal.length - 1].y,
|
||||
unit: unit,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
var value_to_render = Number(this.state.value);
|
||||
return (
|
||||
<div className="single-value-widget">
|
||||
<strong style={{ fontSize: this.props.widget.textSize + 'px' }}>{this.props.widget.name}</strong>
|
||||
<span style={{ fontSize: this.props.widget.textSize + 'px' }}>{Number.isNaN(value_to_render) ? NaN : format('.3s')(value_to_render)}</span>
|
||||
{this.props.widget.showUnit &&
|
||||
<span style={{ fontSize: this.props.widget.textSize + 'px' }}>[{this.state.unit}]</span>
|
||||
<strong style={{ fontSize: this.props.widget.customProperties.textSize + 'px' }}>{this.props.widget.name}</strong>
|
||||
<span style={{ fontSize: this.props.widget.customProperties.textSize + 'px' }}>{Number.isNaN(value_to_render) ? NaN : format('.3s')(value_to_render)}</span>
|
||||
{this.props.widget.customProperties.showUnit &&
|
||||
<span style={{ fontSize: this.props.widget.customProperties.textSize + 'px' }}>[{this.state.unit}]</span>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Add table
Reference in a new issue