add layout to have the process name in the route

This commit is contained in:
Jonathan Rainville 2018-08-03 15:08:13 -04:00 committed by Pascal Precht
parent 2e1791e0f4
commit 548b194224
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
7 changed files with 117 additions and 63 deletions

View File

@ -1,18 +1,23 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {Page} from "tabler-react";
import Loading from "./Loading";
class Process extends Component { class Process extends Component {
render() { render() {
const logs = this.props.logs || []; const logs = this.props.logs;
return ( return (
<div> <Page.Content title={this.props.processName.charAt(0).toUpperCase() + this.props.processName.slice(1)}>
State: {this.props.state} <p className="capitalize">State: {this.props.state}</p>
{!logs &&
<Loading/>}
{logs &&
<div className="logs"> <div className="logs">
{ {
logs.map((item, i) => <p key={i} className={item.logLevel}>{item.msg_clear || item.msg}</p>) logs.map((item, i) => <p key={i} className={item.logLevel}>{item.msg_clear || item.msg}</p>)
} }
</div> </div>}
</div>); </Page.Content>);
} }
} }

View File

@ -0,0 +1,68 @@
import PropTypes from "prop-types";
import React, {Component} from 'react';
import connect from "react-redux/es/connect/connect";
import {NavLink, Route, Switch, withRouter} from 'react-router-dom';
import {
Page,
Grid,
List
} from "tabler-react";
import ProcessesContainer from '../containers/ProcessesContainer';
import Loading from "./Loading";
const routePrefix = '/embark/processes';
class ProcessesLayout extends Component {
render() {
if (!this.props.processes || !this.props.processes.data) {
return <Loading />;
}
const processNames = Object.keys(this.props.processes.data) || [];
return (<Grid.Row>
<Grid.Col md={3}>
<Page.Title className="my-5">Processes</Page.Title>
<div>
<List.Group transparent={true}>
{processNames.map((processName, index) => {
return (<List.GroupItem
className="d-flex align-items-center capitalize"
to={`${routePrefix}/${processName}`}
key={'process-' + processName}
active={index === 0 && this.props.match.isExact === true}
RootComponent={withRouter(NavLink)}
>
{processName}
</List.GroupItem>);
})}
</List.Group>
</div>
</Grid.Col>
<Grid.Col md={9}>
<Switch>
<Route exact path={`${routePrefix}/`} component={ProcessesContainer} />
{processNames.map((processName, index) => {
return (<Route key={'procesRoute-' + index} exact path={`${routePrefix}/${processName}`} component={ProcessesContainer}/>);
})}
</Switch>
</Grid.Col>
</Grid.Row>);
}
}
ProcessesLayout.propTypes = {
processes: PropTypes.object,
match: PropTypes.object
};
function mapStateToProps(state) {
return {processes: state.processes};
}
export default connect(
mapStateToProps
)(ProcessesLayout);

View File

@ -6,11 +6,12 @@ import React, {Component} from 'react';
import history from '../history'; import history from '../history';
import Layout from '../components/Layout'; import Layout from '../components/Layout';
import routes from '../routes'; import routes from '../routes';
import {initBlockHeader} from '../actions'; import {initBlockHeader, fetchProcesses} from '../actions';
class AppContainer extends Component { class AppContainer extends Component {
componentDidMount() { componentDidMount() {
this.props.initBlockHeader(); this.props.initBlockHeader();
this.props.fetchProcesses();
} }
render() { render() {
@ -25,12 +26,14 @@ class AppContainer extends Component {
} }
AppContainer.propTypes = { AppContainer.propTypes = {
initBlockHeader: PropTypes.func initBlockHeader: PropTypes.func,
fetchProcesses: PropTypes.func
}; };
export default connect( export default connect(
null, null,
{ {
initBlockHeader initBlockHeader,
fetchProcesses
}, },
)(AppContainer); )(AppContainer);

View File

@ -1,66 +1,46 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {Tabs, Tab} from 'tabler-react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {fetchProcesses, fetchProcessLogs, listenToProcessLogs} from '../actions'; import {fetchProcessLogs, listenToProcessLogs} from '../actions';
import Loading from '../components/Loading';
import "./css/processContainer.css";
import Process from "../components/Process"; import Process from "../components/Process";
class ProcessesContainer extends Component { class ProcessesContainer extends Component {
componentDidMount() { componentDidMount() {
this.props.fetchProcesses(); // Get correct process name
} const pathParts = this.props.match.path.split('/');
this.processName = pathParts[pathParts.length - 1];
shouldComponentUpdate(nextProps, _nextState) { // If we are not in a specific process page (eg: processes/ root), get first process
if (!this.islistening && nextProps.processes && nextProps.processes.data) { if (Object.keys(this.props.processes.data).indexOf(this.processName) < 0) {
this.islistening = true; this.processName = Object.keys(this.props.processes.data)[0];
Object.keys(nextProps.processes.data).forEach(processName => { }
this.props.fetchProcessLogs(processName);
// Only start watching if we are not already watching // Fetch logs for the process
if (!this.props.processes.data || this.props.fetchProcessLogs(this.processName);
!this.props.processes.data[processName] ||
!this.props.processes.data[processName].isListening // Only start watching if we are not already watching
) { if (!this.props.processes.data[this.processName].isListening) {
this.props.listenToProcessLogs(processName); this.props.listenToProcessLogs(this.processName);
}
});
} }
return true;
} }
render() { render() {
const {processes} = this.props; if (!this.processName) {
if (!processes.data) { return '';
return <Loading />;
} }
const processNames = Object.keys(processes.data);
return ( return (
<div className="processes-container"> <div className="processes-container">
{processes.error && <h1> <Process processName={this.processName}
<i>Error: {processes.error.message || processes.error}</i> state={this.props.processes.data[this.processName].state}
</h1>} logs={this.props.processes.data[this.processName].logs}/>
{processNames && processNames.length && <Tabs initialTab={processNames[0]}>
{processNames.map(processName => {
return (<Tab key={processName} title={processName}>
<Process processName={processName}
state={processes.data[processName].state}
logs={processes.data[processName].logs}/>
</Tab>);
})}
</Tabs>}
</div> </div>
); );
} }
} }
ProcessesContainer.propTypes = { ProcessesContainer.propTypes = {
match: PropTypes.object,
processes: PropTypes.object, processes: PropTypes.object,
fetchProcesses: PropTypes.func,
fetchProcessLogs: PropTypes.func, fetchProcessLogs: PropTypes.func,
listenToProcessLogs: PropTypes.func listenToProcessLogs: PropTypes.func
}; };
@ -72,7 +52,6 @@ function mapStateToProps(state) {
export default connect( export default connect(
mapStateToProps, mapStateToProps,
{ {
fetchProcesses,
fetchProcessLogs, fetchProcessLogs,
listenToProcessLogs listenToProcessLogs
} }

View File

@ -1,9 +1,4 @@
.logs {
.processes-container .nav-link {
text-transform: capitalize;
}
.processes-container .logs {
margin: 10px 0; margin: 10px 0;
background-color: #333333; background-color: #333333;
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
@ -13,15 +8,19 @@
border-radius: 8px; border-radius: 8px;
} }
.processes-container .logs .error { .logs .error {
color: #dc3546; color: #dc3546;
} }
.processes-container .logs .warn { .logs .warn {
color: #fec107; color: #fec107;
} }
.processes-container .logs .debug { .logs .debug {
color: #b7c1cc; color: #b7c1cc;
} }
.processes-container .logs .trace { .logs .trace {
color: #8f98a2; color: #8f98a2;
} }
.capitalize {
text-transform: capitalize;
}

View File

@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'; import {Provider} from 'react-redux';
import "tabler-react/dist/Tabler.css"; import "tabler-react/dist/Tabler.css";
import "./general.css";
import AppContainer from './containers/AppContainer'; import AppContainer from './containers/AppContainer';
import registerServiceWorker from './registerServiceWorker'; import registerServiceWorker from './registerServiceWorker';

View File

@ -4,15 +4,14 @@ import {Route, Switch} from 'react-router-dom';
import Home from './components/Home'; import Home from './components/Home';
import NoMatch from './components/NoMatch'; import NoMatch from './components/NoMatch';
import ExplorerLayout from './components/ExplorerLayout'; import ExplorerLayout from './components/ExplorerLayout';
import ProcessesLayout from './components/ProcessesLayout';
import ProcessesContainer from './containers/ProcessesContainer';
const routes = ( const routes = (
<React.Fragment> <React.Fragment>
<Switch> <Switch>
<Route exact path="/embark/" component={Home} /> <Route exact path="/embark/" component={Home} />
<Route path="/embark/explorer/" component={ExplorerLayout} /> <Route path="/embark/explorer/" component={ExplorerLayout} />
<Route path="/embark/processes/" component={ProcessesContainer} /> <Route path="/embark/processes/" component={ProcessesLayout} />
<Route component={NoMatch} /> <Route component={NoMatch} />
</Switch> </Switch>
</React.Fragment> </React.Fragment>