Adding Console command

This commit is contained in:
Anthony Laibe 2018-08-07 11:48:27 +01:00 committed by Pascal Precht
parent 89b64adc4a
commit 546d7af076
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
9 changed files with 127 additions and 41 deletions

View File

@ -63,6 +63,13 @@ export const processes = {
failure: (error) => action(PROCESSES[FAILURE], {error}) failure: (error) => action(PROCESSES[FAILURE], {error})
}; };
export const COMMANDS = createRequestTypes('COMMANDS');
export const commands = {
post: (command) => action(COMMANDS[REQUEST], {command}),
success: (result) => action(COMMANDS[SUCCESS], {result}),
failure: (error) => action(COMMANDS[FAILURE], {error})
};
// Process logs // Process logs
export const FETCH_PROCESS_LOGS = 'FETCH_PROCESS_LOGS'; export const FETCH_PROCESS_LOGS = 'FETCH_PROCESS_LOGS';
export const RECEIVE_PROCESS_LOGS = 'RECEIVE_PROCESS_LOGS'; export const RECEIVE_PROCESS_LOGS = 'RECEIVE_PROCESS_LOGS';

View File

@ -11,6 +11,20 @@ function get(path, params) {
}); });
} }
function post(path, params) {
return axios.post(constants.httpEndpoint + path, params)
.then((response) => {
return {response};
})
.catch((error) => {
return {response: null, error: error.message || 'Something bad happened'};
});
}
export function postCommand(payload) {
return post('/command', payload);
}
export function fetchAccounts() { export function fetchAccounts() {
return get('/blockchain/accounts'); return get('/blockchain/accounts');
} }

View File

@ -1,27 +1,61 @@
import React from 'react'; import PropTypes from "prop-types";
import {Grid, Card} from 'tabler-react'; import React, {Component} from 'react';
import {Grid, Card, Form} from 'tabler-react';
const Console = () => ( const CommandResult = ({result}) => (
<p className="text__new-line">{result}</p>
);
CommandResult.propTypes = {
result: PropTypes.string
};
class Console extends Component {
constructor(props) {
super(props);
this.state = {value: ''};
}
handleSubmit(event) {
event.preventDefault();
this.props.postCommand(this.state.value);
this.setState({value: ''});
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<Grid.Row cards> <Grid.Row cards>
<Grid.Col> <Grid.Col>
<Card> <Card>
<Card.Header> <Card.Header>
<Card.Title>Console</Card.Title> <Card.Title>Embark console</Card.Title>
</Card.Header> </Card.Header>
<Card.Body> <Card.Body>
<div className="log"> <div>
<p>Welcome!</p> {this.props.commandResults &&
</div> this.props.commandResults.map((result) => <CommandResult key={result} result={result} />)}
<div className="command-line">
<div className="form-group">
<input type="text" className="form-control" name="example-text-input"
placeholder="type a command (e.g help)" />
</div>
</div> </div>
<Form onSubmit={(event) => this.handleSubmit(event)}>
<Form.Input value={this.state.value}
onChange={(event) => this.handleChange(event)}
name="command"
placeholder="Type a command (e.g help)" />
</Form>
</Card.Body> </Card.Body>
</Card> </Card>
</Grid.Col> </Grid.Col>
</Grid.Row> </Grid.Row>
); );
}
}
Console.propTypes = {
postCommand: PropTypes.func,
commandResults: PropTypes.arrayOf(PropTypes.string)
};
export default Console; export default Console;

View File

@ -38,7 +38,7 @@ const Processes = ({processes}) => (
); );
Processes.propTypes = { Processes.propTypes = {
processes: PropTypes.object, processes: PropTypes.object
}; };
export default Processes; export default Processes;

View File

@ -2,6 +2,7 @@ import PropTypes from "prop-types";
import React, {Component} from 'react'; import React, {Component} from 'react';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {Page} from "tabler-react"; import {Page} from "tabler-react";
import {commands as commandsAction} from "../actions";
import Processes from '../components/Processes'; import Processes from '../components/Processes';
import Console from '../components/Console'; import Console from '../components/Console';
@ -12,21 +13,25 @@ class HomeContainer extends Component {
<React.Fragment> <React.Fragment>
<Page.Title className="my-5">Dashboard</Page.Title> <Page.Title className="my-5">Dashboard</Page.Title>
{this.props.processes.data && <Processes processes={this.props.processes.data} />} {this.props.processes.data && <Processes processes={this.props.processes.data} />}
<Console /> <Console postCommand={this.props.postCommand} commandResults={this.props.commandResults} />
</React.Fragment> </React.Fragment>
); );
} }
} }
HomeContainer.propTypes = { HomeContainer.propTypes = {
processes: PropTypes.object processes: PropTypes.object,
postCommand: PropTypes.func,
commandResults: PropTypes.arrayOf(PropTypes.string)
}; };
function mapStateToProps(state) { function mapStateToProps(state) {
return {processes: state.processes}; return {processes: state.processes, commandResults: state.commands.results};
} }
export default connect( export default connect(
mapStateToProps, mapStateToProps,
null, {
postCommand: commandsAction.post
}
)(HomeContainer); )(HomeContainer);

View File

@ -20,3 +20,7 @@
.logs .trace { .logs .trace {
color: #8f98a2; color: #8f98a2;
} }
.text__new-line {
white-space: pre-line;
}

View File

@ -0,0 +1,14 @@
import * as actions from "../actions";
export default function commands(state = {}, action) {
switch (action.type) {
case actions.COMMANDS[actions.SUCCESS]:
return {
...state, error: null, results: [...state.results || [], action.result.data.result]
};
case actions.COMMANDS[actions.FAILURE]:
return Object.assign({}, state, {error: action.error});
default:
return state;
}
}

View File

@ -3,12 +3,14 @@ import processesReducer from './processesReducer';
import accountsReducer from './accountsReducer'; import accountsReducer from './accountsReducer';
import blocksReducer from './blocksReducer'; import blocksReducer from './blocksReducer';
import transactionsReducer from './transactionsReducer'; import transactionsReducer from './transactionsReducer';
import commandsReducer from './commandsReducer';
const rootReducer = combineReducers({ const rootReducer = combineReducers({
accounts: accountsReducer, accounts: accountsReducer,
processes: processesReducer, processes: processesReducer,
blocks: blocksReducer, blocks: blocksReducer,
transactions: transactionsReducer transactions: transactionsReducer,
commands: commandsReducer
}); });
export default rootReducer; export default rootReducer;

View File

@ -3,24 +3,25 @@ import * as api from '../api';
import {eventChannel} from 'redux-saga'; import {eventChannel} from 'redux-saga';
import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects'; import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects';
const {account, accounts, block, blocks, transaction, transactions, processes} = actions; const {account, accounts, block, blocks, transaction, transactions, processes, commands} = actions;
function *fetchEntity(entity, apiFn, id) { function *doRequest(entity, apiFn, payload) {
const {response, error} = yield call(apiFn, id); const {response, error} = yield call(apiFn, payload);
if(response) { if(response) {
yield put(entity.success(response)); yield put(entity.success(response));
} else { } else if (error) {
yield put(entity.failure(error)); yield put(entity.failure(error));
} }
} }
export const fetchAccount = fetchEntity.bind(null, account, api.fetchAccount); export const fetchAccount = doRequest.bind(null, account, api.fetchAccount);
export const fetchBlock = fetchEntity.bind(null, block, api.fetchBlock); export const fetchBlock = doRequest.bind(null, block, api.fetchBlock);
export const fetchTransaction = fetchEntity.bind(null, transaction, api.fetchTransaction); export const fetchTransaction = doRequest.bind(null, transaction, api.fetchTransaction);
export const fetchAccounts = fetchEntity.bind(null, accounts, api.fetchAccounts); export const fetchAccounts = doRequest.bind(null, accounts, api.fetchAccounts);
export const fetchBlocks = fetchEntity.bind(null, blocks, api.fetchBlocks); export const fetchBlocks = doRequest.bind(null, blocks, api.fetchBlocks);
export const fetchTransactions = fetchEntity.bind(null, transactions, api.fetchTransactions); export const fetchTransactions = doRequest.bind(null, transactions, api.fetchTransactions);
export const fetchProcesses = fetchEntity.bind(null, processes, api.fetchProcesses); export const fetchProcesses = doRequest.bind(null, processes, api.fetchProcesses);
export const postCommand = doRequest.bind(null, commands, api.postCommand);
export function *watchFetchTransaction() { export function *watchFetchTransaction() {
yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction); yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction);
@ -50,6 +51,10 @@ export function *watchFetchProcesses() {
yield takeEvery(actions.PROCESSES[actions.REQUEST], fetchProcesses); yield takeEvery(actions.PROCESSES[actions.REQUEST], fetchProcesses);
} }
export function *watchPostCommand() {
yield takeEvery(actions.COMMANDS[actions.REQUEST], postCommand);
}
export function *fetchProcessLogs(action) { export function *fetchProcessLogs(action) {
try { try {
const logs = yield call(api.fetchProcessLogs, action.processName); const logs = yield call(api.fetchProcessLogs, action.processName);
@ -112,6 +117,7 @@ export default function *root() {
fork(watchFetchBlocks), fork(watchFetchBlocks),
fork(watchFetchBlock), fork(watchFetchBlock),
fork(watchFetchTransactions), fork(watchFetchTransactions),
fork(watchFetchTransaction) fork(watchFetchTransaction),
fork(watchPostCommand)
]); ]);
} }