From 6ae1cd7df94fd7f2426e3de7b91ce42b6fbfc719 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 3 Aug 2018 10:59:39 -0400 Subject: [PATCH 1/4] refactor process logs to use saga and put logic in container --- embark-ui/src/actions/index.js | 10 +++ embark-ui/src/api/index.js | 4 ++ embark-ui/src/components/Process.js | 69 ++----------------- .../src/containers/ProcessesContainer.js | 32 +++++++-- embark-ui/src/reducers/processesReducer.js | 44 ++++++++++-- embark-ui/src/sagas/index.js | 16 +++++ 6 files changed, 101 insertions(+), 74 deletions(-) diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index b540a998..322e5c58 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -9,6 +9,9 @@ export const RECEIVE_PROCESSES_ERROR = 'RECEIVE_PROCESSES_ERROR'; // Process logs export const FETCH_PROCESS_LOGS = 'FETCH_PROCESS_LOGS'; export const RECEIVE_PROCESS_LOGS = 'RECEIVE_PROCESS_LOGS'; +export const WATCH_NEW_PROCESS_LOGS = 'WATCH_NEW_PROCESS_LOGS'; +export const IS_LISTENING_PROCESS_LOG = 'IS_LISTENING_PROCESS_LOG'; +export const RECEIVE_NEW_PROCESS_LOG = 'RECEIVE_NEW_PROCESS_LOG'; export const RECEIVE_PROCESS_LOGS_ERROR = 'RECEIVE_PROCESS_LOGS_ERROR'; // Blocks export const FETCH_BLOCKS = 'FETCH_BLOCKS'; @@ -67,6 +70,13 @@ export function fetchProcessLogs(processName) { }; } +export function listenToProcessLogs(processName) { + return { + type: WATCH_NEW_PROCESS_LOGS, + processName + }; +} + export function receiveProcessLogs(processName, logs) { return { type: RECEIVE_PROCESS_LOGS, diff --git a/embark-ui/src/api/index.js b/embark-ui/src/api/index.js index ab46e38f..550eb7fe 100644 --- a/embark-ui/src/api/index.js +++ b/embark-ui/src/api/index.js @@ -21,6 +21,10 @@ export function fetchProcessLogs(processName) { return axios.get(`${constants.httpEndpoint}/process-logs/${processName}`); } +export function webSocketProcess(processName) { + return new WebSocket(constants.wsEndpoint + '/process-logs/' + processName); +} + export function webSocketBlockHeader() { return new WebSocket(`${constants.wsEndpoint}/blockchain/blockHeader`); } diff --git a/embark-ui/src/components/Process.js b/embark-ui/src/components/Process.js index 18000340..02bb6bce 100644 --- a/embark-ui/src/components/Process.js +++ b/embark-ui/src/components/Process.js @@ -1,66 +1,15 @@ import React, {Component} from 'react'; -import connect from "react-redux/es/connect/connect"; -import {fetchProcessLogs} from "../actions"; -import constants from '../constants'; import PropTypes from 'prop-types'; class Process extends Component { - constructor(props) { - super(props); - this.state = { - logs: [] - }; - this.gotOriginalLogs = false; - } - - componentDidMount() { - const self = this; - - this.props.fetchProcessLogs(self.props.processName); - - this.ws = new WebSocket(constants.wsEndpoint + '/process-logs/' + self.props.processName); - - this.ws.onmessage = function(evt) { - const log = JSON.parse(evt.data); - const logs = self.state.logs; - logs.push(log); - self.setState({ - logs - }); - }; - - this.ws.onclose = function() { - console.log(self.props.processName + "Log process connection is closed"); - }; - - window.onbeforeunload = function(_event) { - this.ws.close(); - }; - } - - shouldComponentUpdate(nextProps, _nextState) { - if (!this.gotOriginalLogs && nextProps.logs && nextProps.logs[this.props.processName]) { - const logs = nextProps.logs[this.props.processName].concat(this.state.logs); - this.gotOriginalLogs = true; - this.setState({ - logs - }); - } - return true; - } - - componentWillUnmount() { - this.ws.close(); - this.ws = null; - } - render() { + const logs = this.props.logs || []; return (
State: {this.props.state}
{ - this.state.logs.map((item, i) =>

{item.msg_clear || item.msg}

) + logs.map((item, i) =>

{item.msg_clear || item.msg}

) }
); @@ -70,17 +19,7 @@ class Process extends Component { Process.propTypes = { processName: PropTypes.string.isRequired, state: PropTypes.string.isRequired, - fetchProcessLogs: PropTypes.func, - logs: PropTypes.object + logs: PropTypes.array }; -function mapStateToProps(state) { - return {logs: state.processes.logs}; -} - -export default connect( - mapStateToProps, - { - fetchProcessLogs - } -)(Process); +export default Process; diff --git a/embark-ui/src/containers/ProcessesContainer.js b/embark-ui/src/containers/ProcessesContainer.js index c98bc026..681b3bce 100644 --- a/embark-ui/src/containers/ProcessesContainer.js +++ b/embark-ui/src/containers/ProcessesContainer.js @@ -2,8 +2,7 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; import {Tabs, Tab} from 'tabler-react'; import PropTypes from 'prop-types'; - -import {fetchProcesses} from '../actions'; +import {fetchProcesses, fetchProcessLogs, listenToProcessLogs} from '../actions'; import Loading from '../components/Loading'; import "./css/processContainer.css"; @@ -14,6 +13,23 @@ class ProcessesContainer extends Component { this.props.fetchProcesses(); } + shouldComponentUpdate(nextProps, _nextState) { + if (!this.islistening && nextProps.processes && nextProps.processes.data) { + this.islistening = true; + Object.keys(nextProps.processes.data).forEach(processName => { + this.props.fetchProcessLogs(processName); + // Only start watching if we are not already watching + if (!this.props.processes.data || + !this.props.processes.data[processName] || + !this.props.processes.data[processName].isListening + ) { + this.props.listenToProcessLogs(processName); + } + }); + } + return true; + } + render() { const {processes} = this.props; if (!processes.data) { @@ -30,7 +46,9 @@ class ProcessesContainer extends Component { {processNames && processNames.length && {processNames.map(processName => { return ( - + ); })} } @@ -42,7 +60,9 @@ class ProcessesContainer extends Component { ProcessesContainer.propTypes = { processes: PropTypes.object, - fetchProcesses: PropTypes.func + fetchProcesses: PropTypes.func, + fetchProcessLogs: PropTypes.func, + listenToProcessLogs: PropTypes.func }; function mapStateToProps(state) { @@ -52,6 +72,8 @@ function mapStateToProps(state) { export default connect( mapStateToProps, { - fetchProcesses + fetchProcesses, + fetchProcessLogs, + listenToProcessLogs } )(ProcessesContainer); diff --git a/embark-ui/src/reducers/processesReducer.js b/embark-ui/src/reducers/processesReducer.js index a7ddae2e..397f8254 100644 --- a/embark-ui/src/reducers/processesReducer.js +++ b/embark-ui/src/reducers/processesReducer.js @@ -1,4 +1,11 @@ -import {RECEIVE_PROCESSES, RECEIVE_PROCESSES_ERROR, RECEIVE_PROCESS_LOGS, RECEIVE_PROCESS_LOGS_ERROR} from "../actions"; +import { + RECEIVE_PROCESSES, + RECEIVE_PROCESSES_ERROR, + RECEIVE_PROCESS_LOGS, + RECEIVE_PROCESS_LOGS_ERROR, + RECEIVE_NEW_PROCESS_LOG, + IS_LISTENING_PROCESS_LOG +} from "../actions"; export default function processes(state = {}, action) { switch (action.type) { @@ -9,11 +16,40 @@ export default function processes(state = {}, action) { case RECEIVE_PROCESS_LOGS: return { ...state, - logs: { - ...state.logs, - [action.processName]: action.logs.data + data: { + ...state.data, + [action.processName]: { + ...state.data[action.processName], + logs: action.logs.data + } } }; + case RECEIVE_NEW_PROCESS_LOG: { + const logs = state.data[action.processName].logs || []; + logs.push(action.log); + return { + ...state, + data: { + ...state.data, + [action.processName]: { + ...state.data[action.processName], + logs: logs + } + } + }; + } + case IS_LISTENING_PROCESS_LOG: { + return { + ...state, + data: { + ...state.data, + [action.processName]: { + ...state.data[action.processName], + isListening: true + } + } + }; + } case RECEIVE_PROCESS_LOGS_ERROR: return Object.assign({}, state, {error: action.error}); default: diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index b1868d72..abea8747 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -93,12 +93,28 @@ export function *watchInitBlockHeader() { yield takeEvery(actions.INIT_BLOCK_HEADER, initBlockHeader); } +export function *listenToProcessLogs(action) { + console.log('WATCH', action.processName); + yield put({type: actions.IS_LISTENING_PROCESS_LOG, processName: action.processName}); + const socket = api.webSocketProcess(action.processName); + const channel = yield call(createChannel, socket); + while (true) { + const log = yield take(channel); + yield put({type: actions.RECEIVE_NEW_PROCESS_LOG, processName: action.processName, log}); + } +} + +export function *watchListenToProcessLogs() { + yield takeEvery(actions.WATCH_NEW_PROCESS_LOGS, listenToProcessLogs); +} + export default function *root() { yield all([ fork(watchInitBlockHeader), fork(watchFetchAccounts), fork(watchFetchProcesses), fork(watchFetchProcessLogs), + fork(watchListenToProcessLogs), fork(watchFetchBlocks), fork(watchFetchTransactions) ]); From 92ff8308074c61c32d496f2d46d1710d4d6dc169 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 3 Aug 2018 11:00:13 -0400 Subject: [PATCH 2/4] remove log --- embark-ui/src/sagas/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index abea8747..7160f5a1 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -94,7 +94,6 @@ export function *watchInitBlockHeader() { } export function *listenToProcessLogs(action) { - console.log('WATCH', action.processName); yield put({type: actions.IS_LISTENING_PROCESS_LOG, processName: action.processName}); const socket = api.webSocketProcess(action.processName); const channel = yield call(createChannel, socket); From e5f60ded5d2f2befb5d7625cbaf302d1fa0d8331 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 3 Aug 2018 11:38:44 -0400 Subject: [PATCH 3/4] remove isListening action and just use the watch one --- embark-ui/src/actions/index.js | 1 - embark-ui/src/reducers/processesReducer.js | 4 ++-- embark-ui/src/sagas/index.js | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 322e5c58..0b499aab 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -10,7 +10,6 @@ export const RECEIVE_PROCESSES_ERROR = 'RECEIVE_PROCESSES_ERROR'; export const FETCH_PROCESS_LOGS = 'FETCH_PROCESS_LOGS'; export const RECEIVE_PROCESS_LOGS = 'RECEIVE_PROCESS_LOGS'; export const WATCH_NEW_PROCESS_LOGS = 'WATCH_NEW_PROCESS_LOGS'; -export const IS_LISTENING_PROCESS_LOG = 'IS_LISTENING_PROCESS_LOG'; export const RECEIVE_NEW_PROCESS_LOG = 'RECEIVE_NEW_PROCESS_LOG'; export const RECEIVE_PROCESS_LOGS_ERROR = 'RECEIVE_PROCESS_LOGS_ERROR'; // Blocks diff --git a/embark-ui/src/reducers/processesReducer.js b/embark-ui/src/reducers/processesReducer.js index 397f8254..288c1df8 100644 --- a/embark-ui/src/reducers/processesReducer.js +++ b/embark-ui/src/reducers/processesReducer.js @@ -4,7 +4,7 @@ import { RECEIVE_PROCESS_LOGS, RECEIVE_PROCESS_LOGS_ERROR, RECEIVE_NEW_PROCESS_LOG, - IS_LISTENING_PROCESS_LOG + WATCH_NEW_PROCESS_LOGS } from "../actions"; export default function processes(state = {}, action) { @@ -38,7 +38,7 @@ export default function processes(state = {}, action) { } }; } - case IS_LISTENING_PROCESS_LOG: { + case WATCH_NEW_PROCESS_LOGS: { return { ...state, data: { diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index 7160f5a1..5d0964a2 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -94,7 +94,6 @@ export function *watchInitBlockHeader() { } export function *listenToProcessLogs(action) { - yield put({type: actions.IS_LISTENING_PROCESS_LOG, processName: action.processName}); const socket = api.webSocketProcess(action.processName); const channel = yield call(createChannel, socket); while (true) { From c644cee851748835e74ef5fa842c3447cea9e7ab Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 3 Aug 2018 15:08:13 -0400 Subject: [PATCH 4/4] add layout to have the process name in the route --- embark-ui/src/components/Process.js | 15 ++-- embark-ui/src/components/ProcessesLayout.js | 68 +++++++++++++++++++ embark-ui/src/containers/AppContainer.js | 9 ++- .../src/containers/ProcessesContainer.js | 63 ++++++----------- .../css/processContainer.css => general.css} | 19 +++--- embark-ui/src/index.js | 1 + embark-ui/src/routes.js | 5 +- 7 files changed, 117 insertions(+), 63 deletions(-) create mode 100644 embark-ui/src/components/ProcessesLayout.js rename embark-ui/src/{containers/css/processContainer.css => general.css} (60%) diff --git a/embark-ui/src/components/Process.js b/embark-ui/src/components/Process.js index 02bb6bce..7a73e064 100644 --- a/embark-ui/src/components/Process.js +++ b/embark-ui/src/components/Process.js @@ -1,18 +1,23 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; +import {Page} from "tabler-react"; +import Loading from "./Loading"; class Process extends Component { render() { - const logs = this.props.logs || []; + const logs = this.props.logs; return ( -
- State: {this.props.state} + +

State: {this.props.state}

+ {!logs && + } + {logs &&
{ logs.map((item, i) =>

{item.msg_clear || item.msg}

) } -
-
); + } + ); } } diff --git a/embark-ui/src/components/ProcessesLayout.js b/embark-ui/src/components/ProcessesLayout.js new file mode 100644 index 00000000..25e93774 --- /dev/null +++ b/embark-ui/src/components/ProcessesLayout.js @@ -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 ; + } + const processNames = Object.keys(this.props.processes.data) || []; + return ( + + Processes +
+ + {processNames.map((processName, index) => { + return ( + {processName} + ); + })} + + +
+
+ + + + {processNames.map((processName, index) => { + return (); + })} + + +
); + } +} + +ProcessesLayout.propTypes = { + processes: PropTypes.object, + match: PropTypes.object +}; + +function mapStateToProps(state) { + return {processes: state.processes}; +} + +export default connect( + mapStateToProps +)(ProcessesLayout); + diff --git a/embark-ui/src/containers/AppContainer.js b/embark-ui/src/containers/AppContainer.js index 94c83767..962baa73 100644 --- a/embark-ui/src/containers/AppContainer.js +++ b/embark-ui/src/containers/AppContainer.js @@ -6,11 +6,12 @@ import React, {Component} from 'react'; import history from '../history'; import Layout from '../components/Layout'; import routes from '../routes'; -import {initBlockHeader} from '../actions'; +import {initBlockHeader, fetchProcesses} from '../actions'; class AppContainer extends Component { componentDidMount() { this.props.initBlockHeader(); + this.props.fetchProcesses(); } render() { @@ -25,12 +26,14 @@ class AppContainer extends Component { } AppContainer.propTypes = { - initBlockHeader: PropTypes.func + initBlockHeader: PropTypes.func, + fetchProcesses: PropTypes.func }; export default connect( null, { - initBlockHeader + initBlockHeader, + fetchProcesses }, )(AppContainer); diff --git a/embark-ui/src/containers/ProcessesContainer.js b/embark-ui/src/containers/ProcessesContainer.js index 681b3bce..9f5c3256 100644 --- a/embark-ui/src/containers/ProcessesContainer.js +++ b/embark-ui/src/containers/ProcessesContainer.js @@ -1,66 +1,46 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; -import {Tabs, Tab} from 'tabler-react'; import PropTypes from 'prop-types'; -import {fetchProcesses, fetchProcessLogs, listenToProcessLogs} from '../actions'; -import Loading from '../components/Loading'; +import {fetchProcessLogs, listenToProcessLogs} from '../actions'; -import "./css/processContainer.css"; import Process from "../components/Process"; class ProcessesContainer extends Component { componentDidMount() { - this.props.fetchProcesses(); - } - - shouldComponentUpdate(nextProps, _nextState) { - if (!this.islistening && nextProps.processes && nextProps.processes.data) { - this.islistening = true; - Object.keys(nextProps.processes.data).forEach(processName => { - this.props.fetchProcessLogs(processName); - // Only start watching if we are not already watching - if (!this.props.processes.data || - !this.props.processes.data[processName] || - !this.props.processes.data[processName].isListening - ) { - this.props.listenToProcessLogs(processName); - } - }); + // Get correct process name + const pathParts = this.props.match.path.split('/'); + this.processName = pathParts[pathParts.length - 1]; + // If we are not in a specific process page (eg: processes/ root), get first process + if (Object.keys(this.props.processes.data).indexOf(this.processName) < 0) { + this.processName = Object.keys(this.props.processes.data)[0]; + } + + // Fetch logs for the process + this.props.fetchProcessLogs(this.processName); + + // Only start watching if we are not already watching + if (!this.props.processes.data[this.processName].isListening) { + this.props.listenToProcessLogs(this.processName); } - return true; } render() { - const {processes} = this.props; - if (!processes.data) { - return ; + if (!this.processName) { + return ''; } - - const processNames = Object.keys(processes.data); return (
- {processes.error &&

- Error: {processes.error.message || processes.error} -

} - - {processNames && processNames.length && - {processNames.map(processName => { - return ( - - ); - })} - } - +
); } } ProcessesContainer.propTypes = { + match: PropTypes.object, processes: PropTypes.object, - fetchProcesses: PropTypes.func, fetchProcessLogs: PropTypes.func, listenToProcessLogs: PropTypes.func }; @@ -72,7 +52,6 @@ function mapStateToProps(state) { export default connect( mapStateToProps, { - fetchProcesses, fetchProcessLogs, listenToProcessLogs } diff --git a/embark-ui/src/containers/css/processContainer.css b/embark-ui/src/general.css similarity index 60% rename from embark-ui/src/containers/css/processContainer.css rename to embark-ui/src/general.css index 1510241f..60588a99 100644 --- a/embark-ui/src/containers/css/processContainer.css +++ b/embark-ui/src/general.css @@ -1,9 +1,4 @@ - -.processes-container .nav-link { - text-transform: capitalize; -} - -.processes-container .logs { +.logs { margin: 10px 0; background-color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; @@ -13,15 +8,19 @@ border-radius: 8px; } -.processes-container .logs .error { +.logs .error { color: #dc3546; } -.processes-container .logs .warn { +.logs .warn { color: #fec107; } -.processes-container .logs .debug { +.logs .debug { color: #b7c1cc; } -.processes-container .logs .trace { +.logs .trace { color: #8f98a2; } + +.capitalize { + text-transform: capitalize; +} diff --git a/embark-ui/src/index.js b/embark-ui/src/index.js index 346c9426..40ff2c2d 100644 --- a/embark-ui/src/index.js +++ b/embark-ui/src/index.js @@ -3,6 +3,7 @@ import ReactDOM from 'react-dom'; import {Provider} from 'react-redux'; import "tabler-react/dist/Tabler.css"; +import "./general.css"; import AppContainer from './containers/AppContainer'; import registerServiceWorker from './registerServiceWorker'; diff --git a/embark-ui/src/routes.js b/embark-ui/src/routes.js index 0797357d..c7cee5aa 100644 --- a/embark-ui/src/routes.js +++ b/embark-ui/src/routes.js @@ -4,15 +4,14 @@ import {Route, Switch} from 'react-router-dom'; import Home from './components/Home'; import NoMatch from './components/NoMatch'; import ExplorerLayout from './components/ExplorerLayout'; - -import ProcessesContainer from './containers/ProcessesContainer'; +import ProcessesLayout from './components/ProcessesLayout'; const routes = ( - +