webgme-dss
Version:
Design Studio for Dynamic Systems with Modelica as backend
380 lines (337 loc) • 14 kB
JSX
/* eslint-env browser */
/* globals window */
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import superagent from 'superagent';
import classNames from 'classnames';
import Drawer from '@material-ui/core/Drawer';
import Divider from '@material-ui/core/Divider';
import IconButton from '@material-ui/core/IconButton';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import PlayCircleOutline from '@material-ui/icons/PlayCircleOutline';
import CheckCircle from '@material-ui/icons/CheckCircle';
import AddCircle from '@material-ui/icons/AddCircle';
import Timeline from '@material-ui/icons/Timeline';
import History from '@material-ui/icons/History';
import {withStyles} from '@material-ui/core/styles';
import green from '@material-ui/core/colors/green';
import PartBrowser from 'webgme-react-components/src/components/PartBrowser';
import SystemSimulatorMetadata from '../../plugins/SystemSimulator/metadata.json';
import ModelCheckMetadata from '../../plugins/ModelCheck/metadata.json';
import ModelCheckPlugin from '../../plugins/ModelCheck/ModelCheck';
import getMetaNodeByName from '../gme/utils/getMetaNodeByName';
import {downloadBlobArtifact} from '../gme/utils/saveUrlToDisk';
import {removePlotVariable, toggleLeftDrawer, toggleModelingView, setResultNode, toggleRightDrawer} from '../actions';
import ResultList from './ResultList';
import PluginConfigDialog from '../Dialogs/PluginConfigDialog';
import DomainSelector from '../Dialogs/DomainSelector';
import NotifyDialog from '../Dialogs/NotifyDialog';
import PluginResultDialog from '../Dialogs/PluginResultDialog';
import ProjectHistory from '../containers/Dialogs/ProjectHistory';
import colorHash from '../gme/utils/colorHash';
import {sideDrawer as styles} from '../classes';
const mapStateToProps = state => ({
open: state.leftDrawer,
activeNode: state.activeNode,
modelingView: state.modelingView,
variables: state.plotData.variables,
scale: state.scale,
});
const mapDispatchToProps = dispatch => ({
hide: () => {
dispatch(toggleLeftDrawer(false));
},
show: () => {
dispatch(toggleLeftDrawer(true));
},
removePlotVariable: (varName) => {
dispatch(removePlotVariable(varName));
},
toggleModelingView: (modelView) => {
dispatch(toggleModelingView(modelView));
},
setResultNode: (resultNode) => {
dispatch(setResultNode(resultNode));
},
toggleRightDrawer: (show) => {
dispatch(toggleRightDrawer(show));
},
});
class LeftDrawer extends Component {
static propTypes = {
gmeClient: PropTypes.object.isRequired,
open: PropTypes.bool.isRequired,
classes: PropTypes.object.isRequired,
activeNode: PropTypes.string.isRequired,
scale: PropTypes.number.isRequired,
modelingView: PropTypes.bool.isRequired,
variables: PropTypes.arrayOf(PropTypes.string).isRequired,
removePlotVariable: PropTypes.func.isRequired,
toggleModelingView: PropTypes.func.isRequired,
// setResultNode: PropTypes.func.isRequired,
toggleRightDrawer: PropTypes.func.isRequired,
show: PropTypes.func.isRequired,
hide: PropTypes.func.isRequired,
};
constructor(props) {
super(props);
const {gmeConfig} = this.props.gmeClient;
this.SystemSimulatorMetadata = JSON.parse(JSON.stringify(SystemSimulatorMetadata));
this.SystemSimulatorMetadata.configStructure.forEach((configDesc) => {
if (gmeConfig.plugin.SystemSimulator && gmeConfig.plugin.SystemSimulator[configDesc.name] !== undefined) {
configDesc.value = gmeConfig.plugin.SystemSimulator[configDesc.name];
configDesc.readOnly = true;
}
});
}
state = {
showSimulator: false,
showChecker: false,
showDomainSelector: false,
showHistory: false,
checkResult: null,
};
onUpdateDomains = (data) => {
const {gmeClient} = this.props;
this.setState({showDomainSelector: false});
if (!data) {
// Cancelled
return;
}
const path = [
window.location.origin + gmeClient.mountedPath,
gmeClient.gmeConfig.rest.components.DomainManager.mount,
'updateProject',
].join('/');
superagent.post(path)
.send({
projectId: gmeClient.getActiveProjectId(),
domains: data.domains,
})
.end((err, result) => {
if (err) {
// TODO: we need to show these errors
console.error(err);
} else {
console.log(result.body);
// const [owner, name] = result.body.projectId.split('+');
// this.props.history.push(`/p/${owner}/${name}`);
}
});
};
getCheckResultContent = () => {
const {checkResult} = this.state;
if (checkResult.success === true) {
return (<NotifyDialog
title="Model check success"
text="The model has no issues and can be simulated as such."
onOK={
() => {
this.setState({checkResult: null});
}}
/>);
}
return (<PluginResultDialog
onOK={
() => {
this.setState({checkResult: null});
}
}
result={checkResult}
title="Model check findings"
/>);
};
runModelCheck = (config) => {
const {gmeClient, activeNode} = this.props;
console.log(ModelCheckPlugin);
this.setState({showChecker: false});
if (!config) {
// Cancelled
return;
}
const pluginId = ModelCheckMetadata.id;
const context = gmeClient.getCurrentPluginContext(pluginId, activeNode);
// TODO: Remove when engine is bumped
context.managerConfig.activeNode = activeNode;
gmeClient.runBrowserPlugin(ModelCheckPlugin, context, (err, result) => {
if (err) {
console.error(err);
} else {
console.log('model check finished');
this.setState({checkResult: result});
}
});
};
runSimulator = (config) => {
const {gmeClient, activeNode} = this.props;
const pluginId = this.SystemSimulatorMetadata.id;
this.setState({showSimulator: false});
if (!config) {
// Cancelled
return;
}
if (config.simulationTool === 'Only Code Generation') {
const context = gmeClient.getCurrentPluginContext(pluginId, activeNode);
context.pluginConfig = config;
gmeClient.runServerPlugin(pluginId, context, (err, result) => {
if (err) {
console.error(err);
} else if (result.success) {
downloadBlobArtifact(result.artifacts[0]);
} else {
console.error(result);
}
});
} else {
const simResContainer = getMetaNodeByName(gmeClient, 'SimulationResults');
const simResMeta = getMetaNodeByName(gmeClient, 'SimulationResult');
if (!simResContainer || !simResMeta) {
console.error(new Error('Could not find SimulationResults or SimulationResult in meta...'));
return;
}
gmeClient.startTransaction();
// Create a Simulation Result..
const resId = gmeClient.createNode({
parentId: simResContainer.getId(),
baseId: simResMeta.getId(),
}, {
attributes: {
name: config.executionName,
timeStamp: Date.now(),
},
});
// .. copy over the canvas model
const modelId = gmeClient.copyNode(activeNode, resId);
const uiId = gmeClient.addUI(null, () => {
});
gmeClient.updateTerritory(uiId, {[modelId]: {children: 0}});
gmeClient.completeTransaction('Created simulation results', (err) => {
if (err) {
console.error(err);
return;
}
const context = gmeClient.getCurrentPluginContext(pluginId, modelId);
context.pluginConfig = config;
gmeClient.removeUI(uiId);
this.props.toggleModelingView(false);
this.props.show();
this.props.toggleRightDrawer(false);
gmeClient.runServerPlugin(pluginId, context, (err2, result) => {
if (err2) {
console.error(err2);
} else if (result.success) {
// downloadBlobArtifact(result.artifacts[0]);
} else {
console.error(result);
}
});
});
}
};
render() {
const {
classes, gmeClient, open, modelingView, variables, activeNode, scale,
} = this.props;
let actionButtons;
if (modelingView) {
actionButtons = [
{
id: 'showChecker',
iconClass: <CheckCircle style={{color: green[500]}}/>,
onClick: () => {
this.setState({showChecker: true});
},
},
{
id: 'showSimulator',
iconClass: <PlayCircleOutline color="primary"/>,
onClick: () => {
this.setState({showSimulator: true});
},
},
{
id: 'showDomainSelector',
iconClass: <AddCircle color="secondary"/>,
onClick: () => {
this.setState({showDomainSelector: true});
},
},
{
id: 'showHistory',
iconClass: <History color="primary"/>,
onClick: () => {
this.setState({showHistory: true});
},
},
];
} else if (!open) {
actionButtons = variables.map(variable => ({
id: variable,
iconClass: <Timeline style={{color: colorHash(variable).rgb}}/>,
color: colorHash(variable).rgb,
onClick: () => {
this.props.removePlotVariable(variable);
},
}));
} else {
actionButtons = [];
}
return (
<div>
<Drawer
variant="permanent"
anchor="left"
open={open}
classes={{paper: classNames(classes.drawerPaper, !open && classes.drawerPaperClose)}}
>
<span>
<IconButton onClick={open ? this.props.hide : this.props.show}>
{open ? <ChevronLeftIcon/> : <ChevronRightIcon/>}
</IconButton>
{actionButtons.map(desc => (
<IconButton
key={desc.id}
onClick={desc.onClick}
>
{desc.iconClass}
</IconButton>
))}
</span>
<Divider/>
{modelingView ?
<PartBrowser gmeClient={gmeClient} activeNode={activeNode} minimized={!open} scale={scale}/> :
<ResultList gmeClient={gmeClient} minimized={!open}/>}
</Drawer>
{this.state.showSimulator ?
<PluginConfigDialog
metadata={this.SystemSimulatorMetadata}
onOK={this.runSimulator}
/> : null}
{this.state.showChecker ?
<PluginConfigDialog
metadata={ModelCheckMetadata}
onOK={this.runModelCheck}
fastForward
/> : null}
{this.state.showDomainSelector ?
<DomainSelector
domains={(gmeClient.getProjectInfo().info.kind || '').split(':').slice(1)}
showDomainSelection
title="Update Domains"
onOK={this.onUpdateDomains}
onCancel={this.onUpdateDomains}
/> : null}
{this.state.checkResult ? this.getCheckResultContent() : null}
{this.state.showHistory ? <ProjectHistory
gmeClient={gmeClient}
onOK={() => {
this.setState({showHistory: false});
}}
/> : null}
</div>
);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(LeftDrawer));