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 SUCCESS = 'SUCCESS';
export const FAILURE = 'FAILURE';
@ -92,28 +94,21 @@ export const processes = {
export const COMMANDS = createRequestTypes('COMMANDS');
export const commands = {
post: (command) => action(COMMANDS[REQUEST], {command, noLoading: true}),
success: (command) => action(COMMANDS[SUCCESS], {commands: [{timestamp: new Date().getTime(), ...command}]}),
post: (command) => action(COMMANDS[REQUEST], {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})
};
export const PROCESS_LOGS = createRequestTypes('PROCESS_LOGS');
export const processLogs = {
request: (processName, limit) => action(PROCESS_LOGS[REQUEST], {processName, limit}),
success: (processLogs, payload) => {
return action(PROCESS_LOGS[SUCCESS],
{
ws: !!payload.ws,
processLogs: [
{
process: payload.processName,
timestamp: new Date().getTime(),
logs: processLogs
}
]
}
);
},
request: (processName) => action(PROCESS_LOGS[REQUEST], {processName}),
success: (processLogs) => action(PROCESS_LOGS[SUCCESS], {processLogs}),
failure: (error) => action(PROCESS_LOGS[FAILURE], {error})
};
@ -154,7 +149,7 @@ export const contractFile = {
export const CONTRACT_FUNCTION = createRequestTypes('CONTRACT_FUNCTION');
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}]}),
failure: (error) => action(CONTRACT_FUNCTION[FAILURE], {error})
};

View File

@ -6,14 +6,6 @@ import Convert from 'ansi-to-html';
const convert = new Convert();
const CommandResult = ({result}) => (
<p className="text__new-line">{result}</p>
);
CommandResult.propTypes = {
result: PropTypes.string
};
class Console extends Component {
constructor(props) {
super(props);
@ -31,52 +23,25 @@ class Console extends Component {
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() {
const {processes} = this.props;
return processes
.sort((a, b) => { // ensure the "Embark" tab is displayed first
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>
{
this.getProcessLogs(process.name)
.map((item, i) => <p key={i} className={item.logLevel}
dangerouslySetInnerHTML={{__html: convert.toHtml(item.msg)}}></p>)
}
</Logs>
</Tab>
const {processLogs, processes} = this.props;
return processes.map(process => (
<Tab title={process.name} key={process.name}>
<Logs>
{
processLogs
.filter((item) => item.name === process.name)
.reverse()
.map((item, i) => <p key={i} className={item.logLevel}
dangerouslySetInnerHTML={{__html: convert.toHtml(item.msg)}}></p>)
}
</Logs>
</Tab>
));
}
render() {
const tabs = this.renderTabs();
const commandsResult = this.renderCommandsResult();
const {value} = this.state;
return (
@ -93,7 +58,6 @@ class Console extends Component {
</TabbedHeader>
<TabbedContainer selectedTitle={this.props.activeProcess}>
{tabs}
{commandsResult}
</TabbedContainer>
</React.Fragment>
</Card.Body>
@ -115,10 +79,9 @@ class Console extends Component {
Console.propTypes = {
postCommand: PropTypes.func,
isEmbark: PropTypes.func,
commands: PropTypes.arrayOf(PropTypes.object).isRequired,
processes: PropTypes.arrayOf(PropTypes.object).isRequired,
processLogs: PropTypes.arrayOf(PropTypes.object).isRequired,
updateTab: PropTypes.func
};
export default Console;
export default Console;

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

View File

@ -1,6 +1,7 @@
import {combineReducers} from 'redux';
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 VOID_ADDRESS = '0x0000000000000000000000000000000000000000';
@ -19,7 +20,6 @@ const entitiesDefaultState = {
contractDeploys: [],
contractCompiles: [],
contractLogs: [],
commands: [],
messages: [],
messageChannels: [],
versions: [],
@ -37,7 +37,22 @@ const sorter = {
transactions: function(a, b) {
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) {
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;
},
contractLogs: function(a, b) {
@ -46,9 +61,6 @@ const sorter = {
messages: function(a, b) {
return a.time - b.time;
},
commands: function(a, b) {
return a.timestamp - b.timestamp;
},
files: function(a, b) {
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);
},
processLogs: function(processLog, index, self) {
return index === self.findIndex((p) => p.id === processLog.id) && index <= MAX_ELEMENTS
if (processLog.id !== undefined) {
return index === self.findIndex((p) => p.id === processLog.id) && index <= MAX_ELEMENTS
}
return true;
},
contracts: function(contract, index, self) {
return index === self.findIndex((t) => t.className === contract.className);
@ -103,12 +118,6 @@ const filtrer = {
};
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]) {
return {...state, files: action.files};
}
@ -155,7 +164,7 @@ function errorEntities(state = {}, action) {
}
function loading(_state = false, action) {
return action.type.endsWith(REQUEST) && !action.noLoading;
return action.type.endsWith(REQUEST);
}
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);
}
export function getCommands(state) {
return state.entities.commands;
}
export function getProcesses(state) {
return state.entities.processes;
}
export function getProcessLogs(state) {
const processLogsObj = state.entities.processLogs.reduce((processLogs, processLog) => {
const existingProcessLog = processLogs[processLog.process];
if(!existingProcessLog || processLog.timestamp > existingProcessLog.timestamp){
processLogs[processLog.process] = processLog;
}
return processLogs;
}, {});
return Object.values(processLogsObj);
return state.entities.processLogs;
}
export function getContractLogsByContract(state, contractName) {

View File

@ -241,7 +241,7 @@ export function *listenToProcessLogs(action) {
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) {
return get(`/process-logs/${payload.processName}`, {params: payload, processName: payload.processName, credentials: payload.credentials});
return get(`/process-logs/${payload.processName}`, ...arguments);
}
export function fetchContractLogs() {

View File

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