Use process log ids

This commit is contained in:
Anthony Laibe 2018-10-11 15:19:46 +01:00 committed by Pascal Precht
parent 5d29ab1d42
commit de009db74f
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
9 changed files with 62 additions and 106 deletions

View File

@ -1,3 +1,5 @@
import {EMBARK_PROCESS_NAME} from '../constants';
export const REQUEST = 'REQUEST'; export const REQUEST = 'REQUEST';
export const SUCCESS = 'SUCCESS'; export const SUCCESS = 'SUCCESS';
export const FAILURE = 'FAILURE'; export const FAILURE = 'FAILURE';
@ -92,28 +94,21 @@ export const processes = {
export const COMMANDS = createRequestTypes('COMMANDS'); export const COMMANDS = createRequestTypes('COMMANDS');
export const commands = { export const commands = {
post: (command) => action(COMMANDS[REQUEST], {command, noLoading: true}), post: (command) => action(COMMANDS[REQUEST], {command}),
success: (command) => action(COMMANDS[SUCCESS], {commands: [{timestamp: new Date().getTime(), ...command}]}), success: (command, payload) => {
return action(COMMANDS[SUCCESS], {processLogs: [{
timestamp: new Date().getTime(),
name: EMBARK_PROCESS_NAME,
msg: `${payload.command} > ${command.result}`
}]})
},
failure: (error) => action(COMMANDS[FAILURE], {error}) failure: (error) => action(COMMANDS[FAILURE], {error})
}; };
export const PROCESS_LOGS = createRequestTypes('PROCESS_LOGS'); export const PROCESS_LOGS = createRequestTypes('PROCESS_LOGS');
export const processLogs = { export const processLogs = {
request: (processName, limit) => action(PROCESS_LOGS[REQUEST], {processName, limit}), request: (processName) => action(PROCESS_LOGS[REQUEST], {processName}),
success: (processLogs, payload) => { success: (processLogs) => action(PROCESS_LOGS[SUCCESS], {processLogs}),
return action(PROCESS_LOGS[SUCCESS],
{
ws: !!payload.ws,
processLogs: [
{
process: payload.processName,
timestamp: new Date().getTime(),
logs: processLogs
}
]
}
);
},
failure: (error) => action(PROCESS_LOGS[FAILURE], {error}) failure: (error) => action(PROCESS_LOGS[FAILURE], {error})
}; };
@ -154,7 +149,7 @@ export const contractFile = {
export const CONTRACT_FUNCTION = createRequestTypes('CONTRACT_FUNCTION'); export const CONTRACT_FUNCTION = createRequestTypes('CONTRACT_FUNCTION');
export const contractFunction = { export const contractFunction = {
post: (contractName, method, inputs, gasPrice) => action(CONTRACT_FUNCTION[REQUEST], {contractName, method, inputs, gasPrice, noLoading: true}), post: (contractName, method, inputs, gasPrice) => action(CONTRACT_FUNCTION[REQUEST], {contractName, method, inputs, gasPrice}),
success: (result, payload) => action(CONTRACT_FUNCTION[SUCCESS], {contractFunctions: [{...result, ...payload}]}), success: (result, payload) => action(CONTRACT_FUNCTION[SUCCESS], {contractFunctions: [{...result, ...payload}]}),
failure: (error) => action(CONTRACT_FUNCTION[FAILURE], {error}) failure: (error) => action(CONTRACT_FUNCTION[FAILURE], {error})
}; };

View File

@ -6,14 +6,6 @@ import Convert from 'ansi-to-html';
const convert = new Convert(); const convert = new Convert();
const CommandResult = ({result}) => (
<p className="text__new-line">{result}</p>
);
CommandResult.propTypes = {
result: PropTypes.string
};
class Console extends Component { class Console extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -31,41 +23,15 @@ class Console extends Component {
this.setState({value: event.target.value}); this.setState({value: event.target.value});
} }
getProcessLogs(processName){
const log = this.props.processLogs
.reverse()
.filter(item => item.process === processName);
if(!log.length) return [];
// the selector should have reduced `processLogs` down to one
// record per process, and therefore after filtering, the array
// should have only one item
return log[0].logs;
}
renderCommandsResult(){
const {commands} = this.props;
return (
this.props.isEmbark() &&
commands.map((command, index) => {
return <CommandResult key={index} result={command.result}/>;
})
);
}
renderTabs() { renderTabs() {
const {processes} = this.props; const {processLogs, processes} = this.props;
return processes return processes.map(process => (
.sort((a, b) => { // ensure the "Embark" tab is displayed first <Tab title={process.name} key={process.name}>
if (a.name === 'embark') return -1;
if (b.name === 'embark') return 1;
return 0;
})
.map(process => (
<Tab title={process.name} key={process.name} onClick={(e, x) => this.clickTab(e, x)}>
<Logs> <Logs>
{ {
this.getProcessLogs(process.name) processLogs
.filter((item) => item.name === process.name)
.reverse()
.map((item, i) => <p key={i} className={item.logLevel} .map((item, i) => <p key={i} className={item.logLevel}
dangerouslySetInnerHTML={{__html: convert.toHtml(item.msg)}}></p>) dangerouslySetInnerHTML={{__html: convert.toHtml(item.msg)}}></p>)
} }
@ -76,7 +42,6 @@ class Console extends Component {
render() { render() {
const tabs = this.renderTabs(); const tabs = this.renderTabs();
const commandsResult = this.renderCommandsResult();
const {value} = this.state; const {value} = this.state;
return ( return (
@ -93,7 +58,6 @@ class Console extends Component {
</TabbedHeader> </TabbedHeader>
<TabbedContainer selectedTitle={this.props.activeProcess}> <TabbedContainer selectedTitle={this.props.activeProcess}>
{tabs} {tabs}
{commandsResult}
</TabbedContainer> </TabbedContainer>
</React.Fragment> </React.Fragment>
</Card.Body> </Card.Body>
@ -115,7 +79,6 @@ class Console extends Component {
Console.propTypes = { Console.propTypes = {
postCommand: PropTypes.func, postCommand: PropTypes.func,
isEmbark: PropTypes.func, isEmbark: PropTypes.func,
commands: PropTypes.arrayOf(PropTypes.object).isRequired,
processes: PropTypes.arrayOf(PropTypes.object).isRequired, processes: PropTypes.arrayOf(PropTypes.object).isRequired,
processLogs: PropTypes.arrayOf(PropTypes.object).isRequired, processLogs: PropTypes.arrayOf(PropTypes.object).isRequired,
updateTab: PropTypes.func updateTab: PropTypes.func

View File

@ -0,0 +1 @@
export const EMBARK_PROCESS_NAME = 'embark';

View File

@ -7,10 +7,8 @@ import {commands as commandsAction, listenToProcessLogs, processLogs as processL
import DataWrapper from "../components/DataWrapper"; import DataWrapper from "../components/DataWrapper";
import Processes from '../components/Processes'; import Processes from '../components/Processes';
import Console from '../components/Console'; import Console from '../components/Console';
import {getProcesses, getCommands, getProcessLogs} from "../reducers/selectors"; import {getProcesses, getProcessLogs} from "../reducers/selectors";
import {EMBARK_PROCESS_NAME} from '../constants';
const EMBARK_PROCESS_NAME = 'embark';
const LOG_LIMIT = 50;
class HomeContainer extends Component { class HomeContainer extends Component {
constructor(props) { constructor(props) {
@ -31,8 +29,12 @@ class HomeContainer extends Component {
this.props.stopProcessLogs(this.state.activeProcess) this.props.stopProcessLogs(this.state.activeProcess)
} }
this.props.fetchProcessLogs(processName, LOG_LIMIT); if (processName === EMBARK_PROCESS_NAME) {
if (processName !== EMBARK_PROCESS_NAME) { if (this.props.processes.length === 0) {
this.props.fetchProcessLogs(processName);
}
} else {
this.props.fetchProcessLogs(processName);
this.props.listenToProcessLogs(processName); this.props.listenToProcessLogs(processName);
} }
@ -50,7 +52,6 @@ class HomeContainer extends Component {
<DataWrapper shouldRender={this.props.processes.length > 0 } {...this.props} render={({processes, postCommand, processLogs}) => ( <DataWrapper shouldRender={this.props.processes.length > 0 } {...this.props} render={({processes, postCommand, processLogs}) => (
<Console activeProcess={this.state.activeProcess} <Console activeProcess={this.state.activeProcess}
postCommand={postCommand} postCommand={postCommand}
commands={this.props.commands}
processes={processes} processes={processes}
processLogs={processLogs} processLogs={processLogs}
isEmbark={() => this.isEmbark} isEmbark={() => this.isEmbark}
@ -64,7 +65,6 @@ class HomeContainer extends Component {
HomeContainer.propTypes = { HomeContainer.propTypes = {
processes: PropTypes.arrayOf(PropTypes.object), processes: PropTypes.arrayOf(PropTypes.object),
postCommand: PropTypes.func, postCommand: PropTypes.func,
commands: PropTypes.arrayOf(PropTypes.object),
error: PropTypes.string, error: PropTypes.string,
loading: PropTypes.bool loading: PropTypes.bool
}; };
@ -72,7 +72,6 @@ HomeContainer.propTypes = {
function mapStateToProps(state) { function mapStateToProps(state) {
return { return {
processes: getProcesses(state), processes: getProcesses(state),
commands: getCommands(state),
error: state.errorMessage, error: state.errorMessage,
processLogs: getProcessLogs(state), processLogs: getProcessLogs(state),
loading: state.loading loading: state.loading

View File

@ -1,6 +1,7 @@
import {combineReducers} from 'redux'; import {combineReducers} from 'redux';
import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE, import {REQUEST, SUCCESS, FAILURE, CONTRACT_COMPILE, FILES, LOGOUT, AUTHENTICATE,
FETCH_CREDENTIALS, UPDATE_BASE_ETHER, PROCESS_LOGS} from "../actions"; FETCH_CREDENTIALS, UPDATE_BASE_ETHER} from "../actions";
import {EMBARK_PROCESS_NAME} from '../constants';
const BN_FACTOR = 10000; const BN_FACTOR = 10000;
const VOID_ADDRESS = '0x0000000000000000000000000000000000000000'; const VOID_ADDRESS = '0x0000000000000000000000000000000000000000';
@ -19,7 +20,6 @@ const entitiesDefaultState = {
contractDeploys: [], contractDeploys: [],
contractCompiles: [], contractCompiles: [],
contractLogs: [], contractLogs: [],
commands: [],
messages: [], messages: [],
messageChannels: [], messageChannels: [],
versions: [], versions: [],
@ -37,7 +37,22 @@ const sorter = {
transactions: function(a, b) { transactions: function(a, b) {
return ((BN_FACTOR * b.blockNumber) + b.transactionIndex) - ((BN_FACTOR * a.blockNumber) + a.transactionIndex); return ((BN_FACTOR * b.blockNumber) + b.transactionIndex) - ((BN_FACTOR * a.blockNumber) + a.transactionIndex);
}, },
processes: function(a, b) {
if (a.name === EMBARK_PROCESS_NAME) return -1;
if (b.name === EMBARK_PROCESS_NAME) return 1;
return 0;
},
processLogs: function(a, b) { processLogs: function(a, b) {
if (a.name !== b.name) {
if(a.name < b.name) return -1;
if(a.name > b.name) return 1;
return 0;
}
if (a.id === undefined && b.id === undefined) {
return b.timestamp - a.timestamp;
}
return b.id - a.id; return b.id - a.id;
}, },
contractLogs: function(a, b) { contractLogs: function(a, b) {
@ -46,9 +61,6 @@ const sorter = {
messages: function(a, b) { messages: function(a, b) {
return a.time - b.time; return a.time - b.time;
}, },
commands: function(a, b) {
return a.timestamp - b.timestamp;
},
files: function(a, b) { files: function(a, b) {
if (a.name < b.name) return -1; if (a.name < b.name) return -1;
if (a.name > b.name) return 1; if (a.name > b.name) return 1;
@ -61,7 +73,10 @@ const filtrer = {
return index === self.findIndex((t) => t.name === process.name); return index === self.findIndex((t) => t.name === process.name);
}, },
processLogs: function(processLog, index, self) { processLogs: function(processLog, index, self) {
if (processLog.id !== undefined) {
return index === self.findIndex((p) => p.id === processLog.id) && index <= MAX_ELEMENTS return index === self.findIndex((p) => p.id === processLog.id) && index <= MAX_ELEMENTS
}
return true;
}, },
contracts: function(contract, index, self) { contracts: function(contract, index, self) {
return index === self.findIndex((t) => t.className === contract.className); return index === self.findIndex((t) => t.className === contract.className);
@ -103,12 +118,6 @@ const filtrer = {
}; };
function entities(state = entitiesDefaultState, action) { function entities(state = entitiesDefaultState, action) {
if (action.type === PROCESS_LOGS[SUCCESS] && action.ws === true){
const process = action.processLogs[0].process;
let processLogs = state.processLogs.filter(logs => logs.process === process).sort((a, b) => b.timestamp - a.timestamp)[0];
processLogs.logs.push(action.processLogs[0].logs[0]);
return {...state};
}
if (action.type === FILES[SUCCESS]) { if (action.type === FILES[SUCCESS]) {
return {...state, files: action.files}; return {...state, files: action.files};
} }
@ -155,7 +164,7 @@ function errorEntities(state = {}, action) {
} }
function loading(_state = false, action) { function loading(_state = false, action) {
return action.type.endsWith(REQUEST) && !action.noLoading; return action.type.endsWith(REQUEST);
} }
function compilingContract(state = false, action) { function compilingContract(state = false, action) {

View File

@ -44,23 +44,12 @@ export function getBlock(state, number) {
return state.entities.blocks.find((block) => block.number.toString() === number); return state.entities.blocks.find((block) => block.number.toString() === number);
} }
export function getCommands(state) {
return state.entities.commands;
}
export function getProcesses(state) { export function getProcesses(state) {
return state.entities.processes; return state.entities.processes;
} }
export function getProcessLogs(state) { export function getProcessLogs(state) {
const processLogsObj = state.entities.processLogs.reduce((processLogs, processLog) => { return state.entities.processLogs;
const existingProcessLog = processLogs[processLog.process];
if(!existingProcessLog || processLog.timestamp > existingProcessLog.timestamp){
processLogs[processLog.process] = processLog;
}
return processLogs;
}, {});
return Object.values(processLogsObj);
} }
export function getContractLogsByContract(state, contractName) { export function getContractLogsByContract(state, contractName) {

View File

@ -241,7 +241,7 @@ export function *listenToProcessLogs(action) {
return; return;
} }
yield put(actions.processLogs.success([processLog], {processName: action.processName, ws: true})); yield put(actions.processLogs.success([processLog]));
} }
} }

View File

@ -56,7 +56,7 @@ export function fetchProcesses() {
} }
export function fetchProcessLogs(payload) { export function fetchProcessLogs(payload) {
return get(`/process-logs/${payload.processName}`, {params: payload, processName: payload.processName, credentials: payload.credentials}); return get(`/process-logs/${payload.processName}`, ...arguments);
} }
export function fetchContractLogs() { export function fetchContractLogs() {

View File

@ -84,7 +84,7 @@ class ProcessLauncher {
self.embark.registerAPICall( self.embark.registerAPICall(
'get', 'get',
apiRoute, apiRoute,
(req, res) => { (_req, res) => {
const result = self.logs.map((log, id) => Object.assign(log, {id})).slice(-50); const result = self.logs.map((log, id) => Object.assign(log, {id})).slice(-50);
res.send(JSON.stringify(result)); res.send(JSON.stringify(result));
} }