diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 7104d037..068316da 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -6,6 +6,10 @@ export const RECEIVE_ACCOUNTS_ERROR = 'RECEIVE_ACCOUNTS_ERROR'; export const FETCH_PROCESSES = 'FETCH_PROCESSES'; export const RECEIVE_PROCESSES = 'RECEIVE_PROCESSES'; 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 RECEIVE_PROCESS_LOGS_ERROR = 'RECEIVE_PROCESS_LOGS_ERROR'; // Blocks export const FETCH_BLOCKS = 'FETCH_BLOCKS'; export const RECEIVE_BLOCKS = 'RECEIVE_BLOCKS'; @@ -47,9 +51,32 @@ export function receiveProcesses(processes) { }; } -export function receiveProcessesError() { +export function receiveProcessesError(error) { return { - type: RECEIVE_PROCESSES_ERROR + type: RECEIVE_PROCESSES_ERROR, + error + }; +} + +export function fetchProcessLogs(processName) { + return { + type: FETCH_PROCESS_LOGS, + processName + }; +} + +export function receiveProcessLogs(processName, logs) { + return { + type: RECEIVE_PROCESS_LOGS, + processName, + logs + }; +} + +export function receiveProcessLogsError(error) { + return { + type: RECEIVE_PROCESS_LOGS_ERROR, + error }; } diff --git a/embark-ui/src/api/index.js b/embark-ui/src/api/index.js index c878cec2..4ab0c14d 100644 --- a/embark-ui/src/api/index.js +++ b/embark-ui/src/api/index.js @@ -4,7 +4,7 @@ import constants from '../constants'; const BASE_URL = 'http://localhost:8000/embark-api'; export function fetchAccounts() { - return axios.get(constants.httpEndpoint + 'blockchain/accounts'); + return axios.get(constants.httpEndpoint + '/blockchain/accounts'); } export function fetchBlocks(from) { @@ -16,5 +16,9 @@ export function fetchTransactions(blockFrom) { } export function fetchProcesses() { - return axios.get(constants.httpEndpoint + 'processes'); + return axios.get(constants.httpEndpoint + '/processes'); +} + +export function fetchProcessLogs(processName) { + return axios.get(`${constants.httpEndpoint}/process-logs/${processName}`); } diff --git a/embark-ui/src/components/Process.js b/embark-ui/src/components/Process.js index a1c914b4..18000340 100644 --- a/embark-ui/src/components/Process.js +++ b/embark-ui/src/components/Process.js @@ -1,5 +1,6 @@ import React, {Component} from 'react'; -import {Tab} from "tabler-react"; +import connect from "react-redux/es/connect/connect"; +import {fetchProcessLogs} from "../actions"; import constants from '../constants'; import PropTypes from 'prop-types'; @@ -9,11 +10,15 @@ class Process extends Component { this.state = { logs: [] }; + this.gotOriginalLogs = false; } componentDidMount() { const self = this; - this.ws = new WebSocket(constants.wsEndpoint + 'process-logs/' + self.props.processName); + + 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); @@ -33,6 +38,17 @@ class Process extends Component { }; } + 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; @@ -44,7 +60,7 @@ class Process extends Component { State: {this.props.state}
{ - this.state.logs.map((item, i) =>

{item.msg}

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

{item.msg_clear || item.msg}

) }
); @@ -52,8 +68,19 @@ class Process extends Component { } Process.propTypes = { - processName: PropTypes.string, - state: PropTypes.string + processName: PropTypes.string.isRequired, + state: PropTypes.string.isRequired, + fetchProcessLogs: PropTypes.func, + logs: PropTypes.object }; -export default Process; +function mapStateToProps(state) { + return {logs: state.processes.logs}; +} + +export default connect( + mapStateToProps, + { + fetchProcessLogs + } +)(Process); diff --git a/embark-ui/src/constants.json b/embark-ui/src/constants.json index 06f14ec8..d8fafa6c 100644 --- a/embark-ui/src/constants.json +++ b/embark-ui/src/constants.json @@ -1,4 +1,4 @@ { - "httpEndpoint": "http://localhost:8000/embark-api/", - "wsEndpoint": "ws://localhost:8000/embark-api/" + "httpEndpoint": "http://localhost:8000/embark-api", + "wsEndpoint": "ws://localhost:8000/embark-api" } diff --git a/embark-ui/src/reducers/processesReducer.js b/embark-ui/src/reducers/processesReducer.js index dc189048..a7ddae2e 100644 --- a/embark-ui/src/reducers/processesReducer.js +++ b/embark-ui/src/reducers/processesReducer.js @@ -1,11 +1,21 @@ -import {RECEIVE_PROCESSES, RECEIVE_PROCESSES_ERROR} from "../actions"; +import {RECEIVE_PROCESSES, RECEIVE_PROCESSES_ERROR, RECEIVE_PROCESS_LOGS, RECEIVE_PROCESS_LOGS_ERROR} from "../actions"; export default function processes(state = {}, action) { switch (action.type) { case RECEIVE_PROCESSES: return Object.assign({}, state, {data: action.processes.data}); case RECEIVE_PROCESSES_ERROR: - return Object.assign({}, state, {error: true}); + return Object.assign({}, state, {error: action.error}); + case RECEIVE_PROCESS_LOGS: + return { + ...state, + logs: { + ...state.logs, + [action.processName]: action.logs.data + } + }; + case RECEIVE_PROCESS_LOGS_ERROR: + return Object.assign({}, state, {error: action.error}); default: return state; } diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index c2ad5da7..e242bf3a 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -46,7 +46,7 @@ export function *fetchProcesses() { const processes = yield call(api.fetchProcesses); yield put(actions.receiveProcesses(processes)); } catch (e) { - yield put(actions.receiveProcessesError()); + yield put(actions.receiveProcessesError(e)); } } @@ -54,10 +54,24 @@ export function *watchFetchProcesses() { yield takeEvery(actions.FETCH_PROCESSES, fetchProcesses); } +export function *fetchProcessLogs(action) { + try { + const logs = yield call(api.fetchProcessLogs, action.processName); + yield put(actions.receiveProcessLogs(action.processName, logs)); + } catch (e) { + yield put(actions.receiveProcessLogsError(e)); + } +} + +export function *watchFetchProcessLogs() { + yield takeEvery(actions.FETCH_PROCESS_LOGS, fetchProcessLogs); +} + export default function *root() { yield all([ fork(watchFetchAccounts), fork(watchFetchProcesses), + fork(watchFetchProcessLogs), fork(watchFetchBlocks), fork(watchFetchTransactions) ]); diff --git a/lib/core/processes/processLauncher.js b/lib/core/processes/processLauncher.js index d470ca92..ef3b105f 100644 --- a/lib/core/processes/processLauncher.js +++ b/lib/core/processes/processLauncher.js @@ -21,6 +21,7 @@ class ProcessLauncher { this.silent = options.silent; this.exitCallback = options.exitCallback; this.embark = options.embark; + this.logs = []; this.subscriptions = {}; this._subscribeToMessages(); @@ -54,20 +55,29 @@ class ProcessLauncher { _registerAsPlugin() { const self = this; + const apiRoute = '/embark-api/process-logs/' + self.name; self.embark.registerAPICall( 'ws', - '/embark-api/process-logs/' + self.name, + apiRoute, (ws, _req) => { - self.events.on('log-' + self.name, function(logLevel, msg) { + self.events.on('process-log-' + self.name, function(logLevel, msg) { ws.send(JSON.stringify({msg, msg_clear: msg.stripColors, logLevel}), () => {}); }); } ); + self.embark.registerAPICall( + 'get', + apiRoute, + (req, res) => { + res.send(JSON.stringify(self.logs)); + } + ); } // Translates logs from the child process to the logger _handleLog(msg) { - this.events.emit('log-' + this.name, msg.type, msg.message); + this.events.emit('process-log-' + this.name, msg.type, msg.message); + this.logs.push({msg: msg.message, msg_clear: msg.message.stripColors, logLevel: msg.logLevel}); if (this.silent && msg.type !== 'error') { return; }