From 1bd5174f61db10f1053be44b485cf29d34dd9c91 Mon Sep 17 00:00:00 2001 From: Anthony Laibe Date: Tue, 7 Aug 2018 15:09:55 +0100 Subject: [PATCH] Adding new reducer and selector --- embark-ui/src/actions/index.js | 141 +++++------------- embark-ui/src/api/index.js | 28 ++-- embark-ui/src/components/Console.js | 5 +- embark-ui/src/components/Contract.js | 5 + embark-ui/src/components/ContractLayout.js | 5 + embark-ui/src/components/ContractProfile.js | 11 +- embark-ui/src/components/Contracts.js | 7 +- embark-ui/src/components/DataWrapper.js | 30 ++++ embark-ui/src/components/Process.js | 22 ++- embark-ui/src/components/Processes.js | 13 +- embark-ui/src/components/ProcessesLayout.js | 28 ++-- embark-ui/src/containers/AccountContainer.js | 37 ++--- embark-ui/src/containers/AccountsContainer.js | 25 ++-- embark-ui/src/containers/BlockContainer.js | 36 ++--- embark-ui/src/containers/BlocksContainer.js | 32 ++-- embark-ui/src/containers/ContractContainer.js | 69 ++++----- .../containers/ContractProfileContainer.js | 63 ++++---- .../src/containers/ContractsContainer.js | 43 +++--- embark-ui/src/containers/HomeContainer.js | 21 ++- embark-ui/src/containers/ProcessContainer.js | 55 +++++++ .../src/containers/ProcessesContainer.js | 58 ------- .../src/containers/TransactionContainer.js | 29 ++-- .../src/containers/TransactionsContainer.js | 30 ++-- embark-ui/src/reducers/accountsReducer.js | 26 ---- embark-ui/src/reducers/blocksReducer.js | 32 ---- embark-ui/src/reducers/commandsReducer.js | 14 -- .../src/reducers/contractProfileReducer.js | 12 -- embark-ui/src/reducers/contractReducer.js | 12 -- embark-ui/src/reducers/contractsReducer.js | 12 -- embark-ui/src/reducers/index.js | 99 ++++++++++-- embark-ui/src/reducers/processesReducer.js | 51 ------- embark-ui/src/reducers/selectors.js | 59 ++++++++ embark-ui/src/reducers/transactionsReducer.js | 36 ----- embark-ui/src/sagas/index.js | 73 +++------ lib/core/processes/processLauncher.js | 9 +- lib/core/processes/processManager.js | 12 +- 36 files changed, 534 insertions(+), 706 deletions(-) create mode 100644 embark-ui/src/components/DataWrapper.js create mode 100644 embark-ui/src/containers/ProcessContainer.js delete mode 100644 embark-ui/src/containers/ProcessesContainer.js delete mode 100644 embark-ui/src/reducers/accountsReducer.js delete mode 100644 embark-ui/src/reducers/blocksReducer.js delete mode 100644 embark-ui/src/reducers/commandsReducer.js delete mode 100644 embark-ui/src/reducers/contractProfileReducer.js delete mode 100644 embark-ui/src/reducers/contractReducer.js delete mode 100644 embark-ui/src/reducers/contractsReducer.js delete mode 100644 embark-ui/src/reducers/processesReducer.js create mode 100644 embark-ui/src/reducers/selectors.js delete mode 100644 embark-ui/src/reducers/transactionsReducer.js diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index a11cfa2fe..02c1d74dc 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -1,4 +1,3 @@ -// Accounts export const REQUEST = 'REQUEST'; export const SUCCESS = 'SUCCESS'; export const FAILURE = 'FAILURE'; @@ -24,7 +23,7 @@ export const accounts = { export const ACCOUNT = createRequestTypes('ACCOUNT'); export const account = { request: (address) => action(ACCOUNT[REQUEST], {address}), - success: (account) => action(ACCOUNT[SUCCESS], {account}), + success: (account) => action(ACCOUNT[SUCCESS], {accounts: [account]}), failure: (error) => action(ACCOUNT[FAILURE], {error}) }; @@ -38,7 +37,7 @@ export const blocks = { export const BLOCK = createRequestTypes('BLOCK'); export const block = { request: (blockNumber) => action(BLOCK[REQUEST], {blockNumber}), - success: (block) => action(BLOCK[SUCCESS], {block}), + success: (block) => action(BLOCK[SUCCESS], {blocks: [block]}), failure: (error) => action(BLOCK[FAILURE], {error}) }; @@ -52,7 +51,7 @@ export const transactions = { export const TRANSACTION = createRequestTypes('TRANSACTION'); export const transaction = { request: (hash) => action(TRANSACTION[REQUEST], {hash}), - success: (transaction) => action(TRANSACTION[SUCCESS], {transaction}), + success: (transaction) => action(TRANSACTION[SUCCESS], {transactions: [transaction]}), failure: (error) => action(TRANSACTION[FAILURE], {error}) }; @@ -66,37 +65,41 @@ export const processes = { export const COMMANDS = createRequestTypes('COMMANDS'); export const commands = { post: (command) => action(COMMANDS[REQUEST], {command}), - success: (result) => action(COMMANDS[SUCCESS], {result}), + success: (command) => action(COMMANDS[SUCCESS], {commands: [command]}), failure: (error) => action(COMMANDS[FAILURE], {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 RECEIVE_NEW_PROCESS_LOG = 'RECEIVE_NEW_PROCESS_LOG'; -export const RECEIVE_PROCESS_LOGS_ERROR = 'RECEIVE_PROCESS_LOGS_ERROR'; -// BlockHeader -export const INIT_BLOCK_HEADER = 'INIT_BLOCK_HEADER'; -// Contracts -export const FETCH_CONTRACTS = 'FETCH_CONTRACTS'; -export const RECEIVE_CONTRACTS = 'RECEIVE_CONTRACTS'; -export const RECEIVE_CONTRACTS_ERROR = 'RECEIVE_CONTRACTS_ERROR'; -// Contract -export const FETCH_CONTRACT = 'FETCH_CONTRACT'; -export const RECEIVE_CONTRACT = 'RECEIVE_CONTRACT'; -export const RECEIVE_CONTRACT_ERROR = 'RECEIVE_CONTRACT_ERROR'; -// Contract Profile -export const FETCH_CONTRACT_PROFILE = 'FETCH_CONTRACT_PROFILE'; -export const RECEIVE_CONTRACT_PROFILE = 'RECEIVE_CONTRACT_PROFILE'; -export const RECEIVE_CONTRACT_PROFILE_ERROR = 'RECEIVE_CONTRACT_PROFILE_ERROR'; +export const PROCESS_LOGS = createRequestTypes('PROCESS_LOGS'); +export const processLogs = { + request: (processName) => action(PROCESS_LOGS[REQUEST], {processName}), + success: (processLogs) => action(PROCESS_LOGS[SUCCESS], {processLogs}), + failure: (error) => action(PROCESS_LOGS[FAILURE], {error}) +}; -export function fetchProcessLogs(processName) { - return { - type: FETCH_PROCESS_LOGS, - processName - }; -} +export const CONTRACTS = createRequestTypes('CONTRACTS'); +export const contracts = { + request: () => action(CONTRACTS[REQUEST]), + success: (contracts) => action(CONTRACTS[SUCCESS], {contracts}), + failure: (error) => action(CONTRACTS[FAILURE], {error}) +}; + +export const CONTRACT = createRequestTypes('CONTRACT'); +export const contract = { + request: (contractName) => action(CONTRACT[REQUEST], {contractName}), + success: (contract) => action(CONTRACT[SUCCESS], {contracts: [contract]}), + failure: (error) => action(CONTRACT[FAILURE], {error}) +}; + +export const CONTRACT_PROFILE = createRequestTypes('CONTRACT_PROFILE'); +export const contractProfile = { + request: (contractName) => action(CONTRACT_PROFILE[REQUEST], {contractName}), + success: (contractProfile) => action(CONTRACT_PROFILE[SUCCESS], {contractProfiles: [contractProfile]}), + failure: (error) => action(CONTRACT_PROFILE[FAILURE], {error}) +}; + +// Web Socket +export const WATCH_NEW_PROCESS_LOGS = 'WATCH_NEW_PROCESS_LOGS'; +export const INIT_BLOCK_HEADER = 'INIT_BLOCK_HEADER'; export function listenToProcessLogs(processName) { return { @@ -105,84 +108,8 @@ export function listenToProcessLogs(processName) { }; } -export function receiveProcessLogs(processName, logs) { - return { - type: RECEIVE_PROCESS_LOGS, - processName, - logs - }; -} - -export function receiveProcessLogsError(error) { - return { - type: RECEIVE_PROCESS_LOGS_ERROR, - error - }; -} - export function initBlockHeader(){ return { type: INIT_BLOCK_HEADER }; } - -export function fetchContractProfile(contractName) { - return { - type: FETCH_CONTRACT_PROFILE, - contractName - }; -} - -export function receiveContractProfile(contractProfile) { - return { - type: RECEIVE_CONTRACT_PROFILE, - contractProfile - }; -} - -export function receiveContractProfileError() { - return { - type: RECEIVE_CONTRACT_PROFILE_ERROR - }; -} - -export function fetchContract(contractName) { - return { - type: FETCH_CONTRACT, - contractName - }; -} - -export function receiveContract(contract) { - return { - type: RECEIVE_CONTRACT, - contract - }; -} - -export function receiveContractError() { - return { - type: RECEIVE_CONTRACT_ERROR - }; -} - - -export function fetchContracts() { - return { - type: FETCH_CONTRACTS - }; -} - -export function receiveContracts(contracts) { - return { - type: RECEIVE_CONTRACTS, - contracts - }; -} - -export function receiveContractsError() { - return { - type: RECEIVE_CONTRACTS_ERROR - }; -} - diff --git a/embark-ui/src/api/index.js b/embark-ui/src/api/index.js index 3a97e3e04..d30b7b3bd 100644 --- a/embark-ui/src/api/index.js +++ b/embark-ui/src/api/index.js @@ -53,8 +53,20 @@ export function fetchProcesses() { return get('/processes'); } -export function fetchProcessLogs(processName) { - return axios.get(`${constants.httpEndpoint}/process-logs/${processName}`); +export function fetchProcessLogs(payload) { + return get(`/process-logs/${payload.processName}`); +} + +export function fetchContracts() { + return get('/contracts'); +} + +export function fetchContract(payload) { + return get(`/contract/${payload.contractName}`); +} + +export function fetchContractProfile(payload) { + return get(`/profiler/${payload.contractName}`); } export function webSocketProcess(processName) { @@ -64,15 +76,3 @@ export function webSocketProcess(processName) { export function webSocketBlockHeader() { return new WebSocket(`${constants.wsEndpoint}/blockchain/blockHeader`); } - -export function fetchContract(contractName) { - return axios.get(`${constants.httpEndpoint}/contract/${contractName}`); -} - -export function fetchContracts() { - return axios.get(`${constants.httpEndpoint}/contracts`); -} - -export function fetchContractProfile(contractName) { - return axios.get(`${constants.httpEndpoint}/profiler/${contractName}`); -} diff --git a/embark-ui/src/components/Console.js b/embark-ui/src/components/Console.js index b77ba4b38..99afab3ec 100644 --- a/embark-ui/src/components/Console.js +++ b/embark-ui/src/components/Console.js @@ -36,8 +36,7 @@ class Console extends Component {
- {this.props.commandResults && - this.props.commandResults.map((result) => )} + {this.props.commands.map((command, index) => )}
this.handleSubmit(event)}> ( ); +Contract.propTypes = { + contract: PropTypes.object +}; + export default Contract; diff --git a/embark-ui/src/components/ContractLayout.js b/embark-ui/src/components/ContractLayout.js index d5cf82d2b..e6afe1fbe 100644 --- a/embark-ui/src/components/ContractLayout.js +++ b/embark-ui/src/components/ContractLayout.js @@ -1,3 +1,4 @@ +import PropTypes from "prop-types"; import React from 'react'; import {NavLink, Route, Switch, withRouter} from 'react-router-dom'; import { @@ -59,4 +60,8 @@ const ContractLayout = (props) => ( ); +ContractLayout.propTypes = { + match: PropTypes.object +}; + export default withRouter(ContractLayout); diff --git a/embark-ui/src/components/ContractProfile.js b/embark-ui/src/components/ContractProfile.js index 66217e52b..7e26da530 100644 --- a/embark-ui/src/components/ContractProfile.js +++ b/embark-ui/src/components/ContractProfile.js @@ -1,3 +1,4 @@ +import PropTypes from "prop-types"; import React from 'react'; import { Page, @@ -6,8 +7,8 @@ import { Table } from "tabler-react"; -const ContractProfile = ({contract}) => ( - +const ContractProfile = ({contractProfile}) => ( + @@ -23,7 +24,7 @@ const ContractProfile = ({contract}) => ( {content: "Gas Estimates"} ]} bodyItems={ - contract.methods.map((method) => { + contractProfile.methods.map((method) => { return ([ {content: method.name}, {content: (method.payable === true).toString()}, @@ -41,5 +42,9 @@ const ContractProfile = ({contract}) => ( ); +ContractProfile.propTypes = { + contractProfile: PropTypes.object +}; + export default ContractProfile; diff --git a/embark-ui/src/components/Contracts.js b/embark-ui/src/components/Contracts.js index b8817fee9..fa8be2672 100644 --- a/embark-ui/src/components/Contracts.js +++ b/embark-ui/src/components/Contracts.js @@ -1,3 +1,4 @@ +import PropTypes from "prop-types"; import React from 'react'; import { Page, @@ -25,7 +26,7 @@ const Contracts = ({contracts}) => ( return ([ {content: {contract.name}}, {content: contract.address}, - {content: contract.deploy} + {content: contract.deploy.toString()} ]); }) } @@ -36,5 +37,9 @@ const Contracts = ({contracts}) => ( ); +Contracts.propTypes = { + contracts: PropTypes.arrayOf(PropTypes.object) +}; + export default Contracts; diff --git a/embark-ui/src/components/DataWrapper.js b/embark-ui/src/components/DataWrapper.js new file mode 100644 index 000000000..71eb5719d --- /dev/null +++ b/embark-ui/src/components/DataWrapper.js @@ -0,0 +1,30 @@ +import PropTypes from 'prop-types'; +import React from "react"; + +import Loading from '../components/Loading'; +import Error from '../components/Error'; + +const DataWrapper = ({error, loading, shouldRender, render, ...rest}) => { + if (error) { + return ; + } + + if (loading) { + return ; + } + + if (shouldRender) { + return render(rest); + } + + return ; +}; + +DataWrapper.propTypes = { + error: PropTypes.string, + loading: PropTypes.bool, + render: PropTypes.func, + shouldRender: PropTypes.bool +}; + +export default DataWrapper; diff --git a/embark-ui/src/components/Process.js b/embark-ui/src/components/Process.js index ac197dc8e..6475b0075 100644 --- a/embark-ui/src/components/Process.js +++ b/embark-ui/src/components/Process.js @@ -1,30 +1,26 @@ 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 {processLogs, process}= this.props; return ( - -

State: {this.props.state}

- {!logs && - } - {logs && + +

State: {process.state}

{ - logs.map((item, i) =>

{item.msg_clear || item.msg}

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

{item.msg_clear || item.msg}

) } -
} -
); + +
+ ); } } Process.propTypes = { - processName: PropTypes.string.isRequired, - state: PropTypes.string.isRequired, - logs: PropTypes.array + process: PropTypes.object, + processLogs: PropTypes.arrayOf(PropTypes.object) }; export default Process; diff --git a/embark-ui/src/components/Processes.js b/embark-ui/src/components/Processes.js index aadc0e7b8..e04bd5daa 100644 --- a/embark-ui/src/components/Processes.js +++ b/embark-ui/src/components/Processes.js @@ -11,15 +11,15 @@ function stampClasses(state){ }); } -const Process = ({name, state}) => ( +const Process = ({process}) => (
- +
-

{name}

+

{process.name}

@@ -27,18 +27,17 @@ const Process = ({name, state}) => ( ); Process.propTypes = { - name: PropTypes.string, - state: PropTypes.string + process: PropTypes.object }; const Processes = ({processes}) => ( - {Object.keys(processes).map((name) => )} + {processes.map((process) => )} ); Processes.propTypes = { - processes: PropTypes.object + processes: PropTypes.arrayOf(PropTypes.object) }; export default Processes; diff --git a/embark-ui/src/components/ProcessesLayout.js b/embark-ui/src/components/ProcessesLayout.js index 01b8592e2..422a388ef 100644 --- a/embark-ui/src/components/ProcessesLayout.js +++ b/embark-ui/src/components/ProcessesLayout.js @@ -1,40 +1,38 @@ 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 {NavLink, Route, Switch, withRouter, Redirect} from 'react-router-dom'; import { Page, Grid, List } from "tabler-react"; -import ProcessesContainer from '../containers/ProcessesContainer'; +import ProcessContainer from '../containers/ProcessContainer'; +import {getProcesses} from "../reducers/selectors"; import Loading from "./Loading"; const routePrefix = '/embark/processes'; class ProcessesLayout extends Component { - - render() { - if (!this.props.processes || !this.props.processes.data) { + if (this.props.processes.length === 0) { return ; } - const processNames = Object.keys(this.props.processes.data) || []; return ( Processes
- {processNames.map((processName, index) => { + {this.props.processes.map((process, index) => { return ( - {processName} + {process.name} ); })} @@ -43,10 +41,8 @@ class ProcessesLayout extends Component { - - {processNames.map((processName, index) => { - return (); - })} + } /> + ); @@ -54,12 +50,12 @@ class ProcessesLayout extends Component { } ProcessesLayout.propTypes = { - processes: PropTypes.object, + processes: PropTypes.arrayOf(PropTypes.object), match: PropTypes.object }; function mapStateToProps(state) { - return {processes: state.processes}; + return {processes: getProcesses(state)}; } export default connect( diff --git a/embark-ui/src/containers/AccountContainer.js b/embark-ui/src/containers/AccountContainer.js index 0b291195c..e0b23a6b6 100644 --- a/embark-ui/src/containers/AccountContainer.js +++ b/embark-ui/src/containers/AccountContainer.js @@ -5,9 +5,9 @@ import {withRouter} from 'react-router-dom'; import {account as accountAction} from '../actions'; import Account from '../components/Account'; -import NoMatch from "../components/NoMatch"; +import DataWrapper from "../components/DataWrapper"; import Transactions from '../components/Transactions'; -import Error from '../components/Error'; +import {getAccount, getTransactionsByAccount} from "../reducers/selectors"; class AccountContainer extends Component { componentDidMount() { @@ -15,37 +15,30 @@ class AccountContainer extends Component { } render() { - const {account, error} = this.props; - if (error) { - return ; - } - - if (!account) { - return ; - } - return ( - - - - + ( + + + + + )} /> ); } } function mapStateToProps(state, props) { - if(state.accounts.error) { - return {error: state.accounts.error}; - } - if(state.accounts.data) { - return {account: state.accounts.data.find(account => account.address === props.match.params.address)}; - } - return {}; + return { + account: getAccount(state, props.match.params.address), + transactions: getTransactionsByAccount(state, props.match.params.address), + error: state.errorMessage, + loading: state.loading + }; } AccountContainer.propTypes = { match: PropTypes.object, account: PropTypes.object, + transactions: PropTypes.arrayOf(PropTypes.object), fetchAccount: PropTypes.func, error: PropTypes.string }; diff --git a/embark-ui/src/containers/AccountsContainer.js b/embark-ui/src/containers/AccountsContainer.js index 0aa9fe248..461370986 100644 --- a/embark-ui/src/containers/AccountsContainer.js +++ b/embark-ui/src/containers/AccountsContainer.js @@ -4,8 +4,8 @@ import PropTypes from 'prop-types'; import {accounts as accountsAction} from '../actions'; import Accounts from '../components/Accounts'; -import Loading from '../components/Loading'; -import Error from '../components/Error'; +import DataWrapper from "../components/DataWrapper"; +import {getAccounts} from "../reducers/selectors"; class AccountsContainer extends Component { componentDidMount() { @@ -13,28 +13,23 @@ class AccountsContainer extends Component { } render() { - const {accounts} = this.props; - if (accounts.error) { - return ; - } - - if (!accounts.data) { - return ; - } - return ( - + 0} {...this.props} render={({accounts}) => ( + + )} /> ); } } function mapStateToProps(state) { - return {accounts: state.accounts}; + return {accounts: getAccounts(state), error: state.errorMessage, loading: state.loading}; } AccountsContainer.propTypes = { - accounts: PropTypes.object, - fetchAccounts: PropTypes.func + accounts: PropTypes.arrayOf(PropTypes.object), + fetchAccounts: PropTypes.func, + error: PropTypes.string, + loading: PropTypes.bool }; export default connect( diff --git a/embark-ui/src/containers/BlockContainer.js b/embark-ui/src/containers/BlockContainer.js index 9d8de292c..414a819db 100644 --- a/embark-ui/src/containers/BlockContainer.js +++ b/embark-ui/src/containers/BlockContainer.js @@ -5,9 +5,9 @@ import {withRouter} from 'react-router-dom'; import {block as blockAction} from '../actions'; import Block from '../components/Block'; -import Error from "../components/Error"; -import NoMatch from "../components/NoMatch"; +import DataWrapper from "../components/DataWrapper"; import Transactions from '../components/Transactions'; +import {getBlock, getTransactionsByBlock} from "../reducers/selectors"; class BlockContainer extends Component { componentDidMount() { @@ -15,36 +15,30 @@ class BlockContainer extends Component { } render() { - const {block, error} = this.props; - if (error) { - return ; - } - if (!block) { - return ; - } - return ( - - - - + ( + + + + + )} /> ); } } function mapStateToProps(state, props) { - if(state.blocks.error) { - return {error: state.blocks.error}; - } - if(state.blocks.data) { - return {block: state.blocks.data.find(block => block.number.toString() === props.match.params.blockNumber)}; - } - return {}; + return { + block: getBlock(state, props.match.params.blockNumber), + transactions: getTransactionsByBlock(state, props.match.params.blockNumber), + error: state.errorMessage, + loading: state.loading + }; } BlockContainer.propTypes = { match: PropTypes.object, block: PropTypes.object, + transactions: PropTypes.arrayOf(PropTypes.object), fetchBlock: PropTypes.func, error: PropTypes.string }; diff --git a/embark-ui/src/containers/BlocksContainer.js b/embark-ui/src/containers/BlocksContainer.js index c2c4d2648..f2ada3a6a 100644 --- a/embark-ui/src/containers/BlocksContainer.js +++ b/embark-ui/src/containers/BlocksContainer.js @@ -4,9 +4,9 @@ import PropTypes from 'prop-types'; import {blocks as blocksAction} from '../actions'; import Blocks from '../components/Blocks'; -import Loading from '../components/Loading'; -import LoadMore from '../components/LoadMore'; -import Error from '../components/Error'; +import DataWrapper from "../components/DataWrapper"; +import LoadMore from "../components/LoadMore"; +import {getBlocks} from "../reducers/selectors"; class BlocksContainer extends Component { componentDidMount() { @@ -18,23 +18,19 @@ class BlocksContainer extends Component { } loadMoreFrom() { - let blocks = this.props.blocks.data; + let blocks = this.props.blocks; + if (blocks.length === 0) { + return 0; + } return blocks[blocks.length - 1].number - 1; } render() { - const {blocks} = this.props; - if (blocks.error) { - return ; - } - - if (!blocks.data) { - return ; - } - return ( - + 0} {...this.props} render={({blocks}) => ( + + )} /> {(this.loadMoreFrom() >= 0) ? this.loadMore()} /> : } ); @@ -42,12 +38,14 @@ class BlocksContainer extends Component { } function mapStateToProps(state) { - return {blocks: state.blocks}; + return {blocks: getBlocks(state), error: state.errorMessage, loading: state.loading}; } BlocksContainer.propTypes = { - blocks: PropTypes.object, - fetchBlocks: PropTypes.func + blocks: PropTypes.arrayOf(PropTypes.object), + fetchBlocks: PropTypes.func, + error: PropTypes.string, + loading: PropTypes.bool }; export default connect( diff --git a/embark-ui/src/containers/ContractContainer.js b/embark-ui/src/containers/ContractContainer.js index 125079bed..e263f1a01 100644 --- a/embark-ui/src/containers/ContractContainer.js +++ b/embark-ui/src/containers/ContractContainer.js @@ -1,48 +1,45 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { fetchContract } from '../actions'; +import React, {Component} from 'react'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; +import {withRouter} from 'react-router-dom'; + +import {contract as contractAction} from '../actions'; import Contract from '../components/Contract'; -import { withRouter } from 'react-router' +import DataWrapper from "../components/DataWrapper"; +import {getContract} from "../reducers/selectors"; class ContractContainer extends Component { - componentWillMount() { + componentDidMount() { this.props.fetchContract(this.props.match.params.contractName); } render() { - const {contract} = this.props; - if (!contract.data) { - return ( -

- Loading contract... -

- ); - } - - if (contract.error) { - return ( -

- Error API... -

- ); - } - return ( - + ( + + )} /> ); } +} + +function mapStateToProps(state, props) { + return { + contract: getContract(state, props.match.params.contractName), + error: state.errorMessage, + loading: state.loading + }; +} + +ContractContainer.propTypes = { + match: PropTypes.object, + contract: PropTypes.object, + fetchContract: PropTypes.func, + error: PropTypes.string }; -function mapStateToProps(state) { - return { contract: state.contract } -}; - -export default compose( - connect( - mapStateToProps, - {fetchContract} - ), - withRouter -)(ContractContainer); - +export default withRouter(connect( + mapStateToProps, + { + fetchContract: contractAction.request + } +)(ContractContainer)); diff --git a/embark-ui/src/containers/ContractProfileContainer.js b/embark-ui/src/containers/ContractProfileContainer.js index 8af6b3907..723d2ae24 100644 --- a/embark-ui/src/containers/ContractProfileContainer.js +++ b/embark-ui/src/containers/ContractProfileContainer.js @@ -1,48 +1,45 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { fetchContractProfile } from '../actions'; +import React, {Component} from 'react'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; +import {withRouter} from 'react-router-dom'; + +import {contractProfile as contractProfileAction} from '../actions'; import ContractProfile from '../components/ContractProfile'; -import { withRouter } from 'react-router'; +import DataWrapper from "../components/DataWrapper"; +import {getContractProfile} from "../reducers/selectors"; class ContractProfileContainer extends Component { - componentWillMount() { + componentDidMount() { this.props.fetchContractProfile(this.props.match.params.contractName); } render() { - const { contractProfile } = this.props; - if (!contractProfile.data) { - return ( -

- Loading contract profile... -

- ); - } - - if (contractProfile.data.error) { - return ( -

- Error API... -

- ); - } - return ( - + ( + + )} /> ); } } -function mapStateToProps(state) { - return { contractProfile: state.contractProfile }; +function mapStateToProps(state, props) { + return { + contractProfile: getContractProfile(state, props.match.params.contractName), + error: state.errorMessage, + loading: state.loading + }; } -export default compose( - connect( - mapStateToProps, - { fetchContractProfile } - ), - withRouter -)(ContractProfileContainer); +ContractProfileContainer.propTypes = { + match: PropTypes.object, + contractProfile: PropTypes.object, + fetchContractProfile: PropTypes.func, + error: PropTypes.string +}; +export default withRouter(connect( + mapStateToProps, + { + fetchContractProfile: contractProfileAction.request + } +)(ContractProfileContainer)); diff --git a/embark-ui/src/containers/ContractsContainer.js b/embark-ui/src/containers/ContractsContainer.js index 6b9b9a908..1fcac3605 100644 --- a/embark-ui/src/containers/ContractsContainer.js +++ b/embark-ui/src/containers/ContractsContainer.js @@ -1,45 +1,38 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import { fetchContracts } from '../actions'; +import React, {Component} from 'react'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; + +import {contracts as contractsAction} from '../actions'; import Contracts from '../components/Contracts'; +import DataWrapper from "../components/DataWrapper"; +import {getContracts} from "../reducers/selectors"; class ContractsContainer extends Component { - componentWillMount() { + componentDidMount() { this.props.fetchContracts(); } render() { - const { contracts } = this.props; - if (!contracts.data) { - return ( -

- Loading contracts... -

- ); - } - - if (contracts.error) { - return ( -

- Error API... -

- ); - } - return ( - + 0} {...this.props} render={({contracts}) => ( + + )} /> ); } } function mapStateToProps(state) { - return { contracts: state.contracts }; + return {contracts: getContracts(state), error: state.errorMessage, loading: state.loading}; } +ContractsContainer.propTypes = { + contracts: PropTypes.object, + fetchContracts: PropTypes.func +}; + export default connect( mapStateToProps, { - fetchContracts + fetchContracts: contractsAction.request }, )(ContractsContainer); - diff --git a/embark-ui/src/containers/HomeContainer.js b/embark-ui/src/containers/HomeContainer.js index 246ea5127..a9d91c034 100644 --- a/embark-ui/src/containers/HomeContainer.js +++ b/embark-ui/src/containers/HomeContainer.js @@ -2,31 +2,40 @@ import PropTypes from "prop-types"; import React, {Component} from 'react'; import {connect} from 'react-redux'; import {Page} from "tabler-react"; -import {commands as commandsAction} from "../actions"; +import {commands as commandsAction} from "../actions"; +import DataWrapper from "../components/DataWrapper"; import Processes from '../components/Processes'; import Console from '../components/Console'; +import {getProcesses, getCommands} from "../reducers/selectors"; class HomeContainer extends Component { render() { return ( Dashboard - {this.props.processes.data && } - + 0 } {...this.props} render={({processes}) => ( + + )} /> + ); } } HomeContainer.propTypes = { - processes: PropTypes.object, + processes: PropTypes.arrayOf(PropTypes.object), postCommand: PropTypes.func, - commandResults: PropTypes.arrayOf(PropTypes.string) + commands: PropTypes.arrayOf(PropTypes.object) }; function mapStateToProps(state) { - return {processes: state.processes, commandResults: state.commands.results}; + return { + processes: getProcesses(state), + commands: getCommands(state), + error: state.errorMessage, + loading: state.loading + }; } export default connect( diff --git a/embark-ui/src/containers/ProcessContainer.js b/embark-ui/src/containers/ProcessContainer.js new file mode 100644 index 000000000..37baf5dfa --- /dev/null +++ b/embark-ui/src/containers/ProcessContainer.js @@ -0,0 +1,55 @@ +import React, {Component} from 'react'; +import {connect} from 'react-redux'; +import PropTypes from 'prop-types'; +import {withRouter} from "react-router-dom"; +import {processLogs as processLogsAction, listenToProcessLogs} from '../actions'; +import DataWrapper from "../components/DataWrapper"; +import Process from "../components/Process"; +import {getProcess, getProcessLogsByProcess} from "../reducers/selectors"; + +class ProcessContainer extends Component { + componentDidMount() { + if (this.props.process.state === 'running' && this.props.processLogs.length === 0) { + this.props.fetchProcessLogs(this.props.match.params.processName); + this.props.listenToProcessLogs(this.props.match.params.processName); + } + } + + render() { + return ( + ( +
+ +
+ )} /> + ); + } +} + +ProcessContainer.propTypes = { + fetchProcessLogs: PropTypes.func, + listenToProcessLogs: PropTypes.func, + process: PropTypes.object, + processLogs: PropTypes.arrayOf(PropTypes.object), + error: PropTypes.string, + loading: PropTypes.bool, + match: PropTypes.object +}; + +function mapStateToProps(state, props) { + return { + process: getProcess(state, props.match.params.processName), + processLogs: getProcessLogsByProcess(state, props.match.params.processName), + error: state.errorMessage, + loading: state.loading + }; +} + +export default withRouter(connect( + mapStateToProps, + { + fetchProcessLogs: processLogsAction.request, + listenToProcessLogs + } +)(ProcessContainer)); diff --git a/embark-ui/src/containers/ProcessesContainer.js b/embark-ui/src/containers/ProcessesContainer.js deleted file mode 100644 index 9f5c32569..000000000 --- a/embark-ui/src/containers/ProcessesContainer.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, {Component} from 'react'; -import {connect} from 'react-redux'; -import PropTypes from 'prop-types'; -import {fetchProcessLogs, listenToProcessLogs} from '../actions'; - -import Process from "../components/Process"; - -class ProcessesContainer extends Component { - componentDidMount() { - // 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); - } - } - - render() { - if (!this.processName) { - return ''; - } - return ( -
- -
- ); - } -} - -ProcessesContainer.propTypes = { - match: PropTypes.object, - processes: PropTypes.object, - fetchProcessLogs: PropTypes.func, - listenToProcessLogs: PropTypes.func -}; - -function mapStateToProps(state) { - return {processes: state.processes}; -} - -export default connect( - mapStateToProps, - { - fetchProcessLogs, - listenToProcessLogs - } -)(ProcessesContainer); diff --git a/embark-ui/src/containers/TransactionContainer.js b/embark-ui/src/containers/TransactionContainer.js index 323445496..d37c6ce64 100644 --- a/embark-ui/src/containers/TransactionContainer.js +++ b/embark-ui/src/containers/TransactionContainer.js @@ -4,9 +4,9 @@ import PropTypes from 'prop-types'; import {withRouter} from 'react-router-dom'; import {transaction as transactionAction} from '../actions'; -import Error from "../components/Error"; -import NoMatch from "../components/NoMatch"; import Transaction from '../components/Transaction'; +import DataWrapper from "../components/DataWrapper"; +import {getTransaction} from "../reducers/selectors"; class TransactionContainer extends Component { componentDidMount() { @@ -14,35 +14,26 @@ class TransactionContainer extends Component { } render() { - const {transaction, error} = this.props; - if (error) { - return ; - } - if (!transaction) { - return ; - } - return ( - + ( - + )} /> ); } } function mapStateToProps(state, props) { - if(state.transactions.error) { - return {error: state.transactions.error}; - } - if(state.transactions.data) { - return {transaction: state.transactions.data.find(transaction => transaction.hash === props.match.params.hash)}; - } - return {}; + return { + transaction: getTransaction(state, props.match.params.hash), + error: state.errorMessage, + loading: state.loading + }; } TransactionContainer.propTypes = { match: PropTypes.object, transaction: PropTypes.object, + transactions: PropTypes.arrayOf(PropTypes.object), fetchTransaction: PropTypes.func, error: PropTypes.string }; diff --git a/embark-ui/src/containers/TransactionsContainer.js b/embark-ui/src/containers/TransactionsContainer.js index 01c6eebd0..402fc1e84 100644 --- a/embark-ui/src/containers/TransactionsContainer.js +++ b/embark-ui/src/containers/TransactionsContainer.js @@ -3,10 +3,10 @@ import {connect} from 'react-redux'; import PropTypes from 'prop-types'; import {transactions as transactionsAction} from '../actions'; +import LoadMore from "../components/LoadMore"; import Transactions from '../components/Transactions'; -import Loading from '../components/Loading'; -import LoadMore from '../components/LoadMore'; -import Error from '../components/Error'; +import DataWrapper from "../components/DataWrapper"; +import {getTransactions} from "../reducers/selectors"; class TransactionsContainer extends Component { componentDidMount() { @@ -18,23 +18,19 @@ class TransactionsContainer extends Component { } loadMoreFrom() { - let transactions = this.props.transactions.data; + let transactions = this.props.transactions; + if (transactions.length === 0) { + return 0; + } return transactions[transactions.length - 1].blockNumber - 1; } render() { - const {transactions} = this.props; - if (transactions.error) { - return ; - } - - if (!transactions.data) { - return ; - } - return ( - + 0} {...this.props} render={({transactions}) => ( + + )} /> {(this.loadMoreFrom() > 0) ? this.loadMore()} /> : } ); @@ -42,12 +38,14 @@ class TransactionsContainer extends Component { } function mapStateToProps(state) { - return {transactions: state.transactions}; + return {transactions: getTransactions(state), error: state.errorMessage, loading: state.loading}; } TransactionsContainer.propTypes = { transactions: PropTypes.object, - fetchTransactions: PropTypes.func + fetchTransactions: PropTypes.func, + error: PropTypes.string, + loading: PropTypes.bool }; export default connect( diff --git a/embark-ui/src/reducers/accountsReducer.js b/embark-ui/src/reducers/accountsReducer.js deleted file mode 100644 index 49f297537..000000000 --- a/embark-ui/src/reducers/accountsReducer.js +++ /dev/null @@ -1,26 +0,0 @@ -import * as actions from "../actions"; - -function filterAccount(account, index, self) { - return index === self.findIndex((a) => a.address === account.address); -} - -export default function accounts(state = {}, action) { - switch (action.type) { - case actions.ACCOUNTS[actions.SUCCESS]: - return { - ...state, error: null, data: [...action.accounts.data, ...state.data || []] - .filter(filterAccount) - }; - case actions.ACCOUNTS[actions.FAILURE]: - return Object.assign({}, state, {error: action.error}); - case actions.ACCOUNT[actions.SUCCESS]: - return { - ...state, error: null, data: [action.account.data, ...state.data || []] - .filter(filterAccount) - }; - case actions.ACCOUNT[actions.FAILURE]: - return Object.assign({}, state, {error: action.error}); - default: - return state; - } -} diff --git a/embark-ui/src/reducers/blocksReducer.js b/embark-ui/src/reducers/blocksReducer.js deleted file mode 100644 index 6e9102cc3..000000000 --- a/embark-ui/src/reducers/blocksReducer.js +++ /dev/null @@ -1,32 +0,0 @@ -import * as actions from "../actions"; - -function sortBlock(a, b) { - return b.number - a.number; -} - -function filterBlock(block, index, self) { - return index === self.findIndex((t) => t.number === block.number); -} - -export default function blocks(state = {}, action) { - switch (action.type) { - case actions.BLOCKS[actions.SUCCESS]: - return { - ...state, error: null, data: [...action.blocks.data, ...state.data || []] - .filter(filterBlock) - .sort(sortBlock) - }; - case actions.BLOCKS[actions.FAILURE]: - return Object.assign({}, state, {error: action.error}); - case actions.BLOCK[actions.SUCCESS]: - return { - ...state, error: null, data: [action.block.data, ...state.data || []] - .filter(filterBlock) - .sort(sortBlock) - }; - case actions.BLOCK[actions.FAILURE]: - return Object.assign({}, state, {error: action.error}); - default: - return state; - } -} diff --git a/embark-ui/src/reducers/commandsReducer.js b/embark-ui/src/reducers/commandsReducer.js deleted file mode 100644 index 5a34d2792..000000000 --- a/embark-ui/src/reducers/commandsReducer.js +++ /dev/null @@ -1,14 +0,0 @@ -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; - } -} diff --git a/embark-ui/src/reducers/contractProfileReducer.js b/embark-ui/src/reducers/contractProfileReducer.js deleted file mode 100644 index 888038da6..000000000 --- a/embark-ui/src/reducers/contractProfileReducer.js +++ /dev/null @@ -1,12 +0,0 @@ -import {RECEIVE_CONTRACT_PROFILE, RECEIVE_CONTRACT_PROFILE_ERROR} from "../actions"; - -export default function contractProfile(state = {}, action) { - switch (action.type) { - case RECEIVE_CONTRACT_PROFILE: - return Object.assign({}, state, {data: action.contractProfile.data}); - case RECEIVE_CONTRACT_PROFILE_ERROR: - return Object.assign({}, state, {error: true}); - default: - return state; - } -} diff --git a/embark-ui/src/reducers/contractReducer.js b/embark-ui/src/reducers/contractReducer.js deleted file mode 100644 index cb3a4ce96..000000000 --- a/embark-ui/src/reducers/contractReducer.js +++ /dev/null @@ -1,12 +0,0 @@ -import {RECEIVE_CONTRACT, RECEIVE_CONTRACT_ERROR} from "../actions"; - -export default function contract(state = {}, action) { - switch (action.type) { - case RECEIVE_CONTRACT: - return Object.assign({}, state, {data: action.contract.data}); - case RECEIVE_CONTRACT_ERROR: - return Object.assign({}, state, {error: true}); - default: - return state; - } -} diff --git a/embark-ui/src/reducers/contractsReducer.js b/embark-ui/src/reducers/contractsReducer.js deleted file mode 100644 index cf37d9c56..000000000 --- a/embark-ui/src/reducers/contractsReducer.js +++ /dev/null @@ -1,12 +0,0 @@ -import {RECEIVE_CONTRACTS, RECEIVE_CONTRACTS_ERROR} from "../actions"; - -export default function contracts(state = {}, action) { - switch (action.type) { - case RECEIVE_CONTRACTS: - return Object.assign({}, state, {data: action.contracts.data}); - case RECEIVE_CONTRACTS_ERROR: - return Object.assign({}, state, {error: true}); - default: - return state; - } -} diff --git a/embark-ui/src/reducers/index.js b/embark-ui/src/reducers/index.js index 8380dfbea..1caea3553 100644 --- a/embark-ui/src/reducers/index.js +++ b/embark-ui/src/reducers/index.js @@ -1,22 +1,89 @@ import {combineReducers} from 'redux'; -import processesReducer from './processesReducer'; -import accountsReducer from './accountsReducer'; -import blocksReducer from './blocksReducer'; -import transactionsReducer from './transactionsReducer'; -import commandsReducer from './commandsReducer'; -import contractsReducer from './contractsReducer'; -import contractReducer from './contractReducer'; -import contractProfileReducer from './contractProfileReducer'; +import {REQUEST} from "../actions"; + +const BN_FACTOR = 10000; + +const entitiesDefaultState = { + accounts: [], + blocks: [], + transactions: [], + processes: [], + processLogs: [], + contracts: [], + contractProfiles: [], + commands: [] +}; + +const sorter = { + blocks: function(a, b) { + return b.number - a.number; + }, + transactions: function(a, b) { + return ((BN_FACTOR * b.blockNumber) + b.transactionIndex) - ((BN_FACTOR * a.blockNumber) + a.transactionIndex); + }, + processLogs: function(a, b) { + return a.timestamp - b.timestamp; + } +}; + +const filtrer = { + processes: function(process, index, self) { + return index === self.findIndex((t) => t.name === process.name); + }, + contracts: function(contract, index, self) { + return index === self.findIndex((t) => t.name === contract.name); + }, + accounts: function(account, index, self) { + return index === self.findIndex((t) => t.address === account.address); + }, + blocks: function(block, index, self) { + return index === self.findIndex((t) => t.number === block.number); + }, + transactions: function(tx, index, self) { + return index === self.findIndex((t) => ( + t.blockNumber === tx.blockNumber && t.transactionIndex === tx.transactionIndex + )); + } +}; + +function entities(state = entitiesDefaultState, action) { + for (let name of Object.keys(state)) { + let filter = filtrer[name] || (() => true); + let sort = sorter[name] || (() => true); + if (action[name] && action[name].length > 1) { + return {...state, [name]: [...action[name], ...state[name]].filter(filter).sort(sort)}; + } + if (action[name] && action[name].length === 1) { + let entity = action[name][0]; + let nested = Object.keys(state).reduce((acc, entityName) => { + if (entity[entityName] && entity[entityName].length > 0) { + let entityFilter = filtrer[entityName] || (() => true); + let entitySort = sorter[entityName] || (() => true); + acc[entityName] = [...entity[entityName], ...state[entityName]].filter(entityFilter).sort(entitySort); + } + return acc; + }, {}); + return { + ...state, ...nested, [name]: [...action[name], ...state[name]].filter(filter).sort(sort) + }; + } + } + + return state; +} + +function errorMessage(state = null, action) { + return action.error || state; +} + +function loading(_state = false, action) { + return action.type.endsWith(REQUEST); +} const rootReducer = combineReducers({ - accounts: accountsReducer, - processes: processesReducer, - contracts: contractsReducer, - contract: contractReducer, - contractProfile: contractProfileReducer, - blocks: blocksReducer, - transactions: transactionsReducer, - commands: commandsReducer + entities, + loading, + errorMessage }); export default rootReducer; diff --git a/embark-ui/src/reducers/processesReducer.js b/embark-ui/src/reducers/processesReducer.js deleted file mode 100644 index 4384316bf..000000000 --- a/embark-ui/src/reducers/processesReducer.js +++ /dev/null @@ -1,51 +0,0 @@ -import * as actions from "../actions"; - -export default function processes(state = {}, action) { - switch (action.type) { - case actions.PROCESSES[actions.SUCCESS]: - return Object.assign({}, state, {data: action.processes.data}); - case actions.PROCESSES[actions.FAILURE]: - return Object.assign({}, state, {error: action.error}); - case actions.RECEIVE_PROCESS_LOGS: - return { - ...state, - data: { - ...state.data, - [action.processName]: { - ...state.data[action.processName], - logs: action.logs.data - } - } - }; - case actions.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 actions.WATCH_NEW_PROCESS_LOGS: { - return { - ...state, - data: { - ...state.data, - [action.processName]: { - ...state.data[action.processName], - isListening: true - } - } - }; - } - case actions.RECEIVE_PROCESS_LOGS_ERROR: - return Object.assign({}, state, {error: action.error}); - default: - return state; - } -} diff --git a/embark-ui/src/reducers/selectors.js b/embark-ui/src/reducers/selectors.js new file mode 100644 index 000000000..81cd9f9b8 --- /dev/null +++ b/embark-ui/src/reducers/selectors.js @@ -0,0 +1,59 @@ +export function getAccounts(state) { + return state.entities.accounts; +} + +export function getAccount(state, address) { + return state.entities.accounts.find((account) => account.address === address); +} + +export function getTransactions(state) { + return state.entities.transactions; +} + +export function getTransaction(state, hash) { + return state.entities.transactions.find((transaction) => transaction.hash === hash); +} + +export function getTransactionsByAccount(state, address) { + return state.entities.transactions.filter((transaction) => transaction.from === address); +} + +export function getTransactionsByBlock(state, blockNumber) { + return state.entities.transactions.filter((transaction) => transaction.blockNumber.toString() === blockNumber); +} + +export function getBlocks(state) { + return state.entities.blocks; +} + +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 getProcess(state, name) { + return state.entities.processes.find((process) => process.name === name); +} + +export function getProcessLogsByProcess(state, processName) { + return state.entities.processLogs.filter((processLog => processLog.name === processName)); +} + +export function getContracts(state) { + return state.entities.contracts; +} + +export function getContract(state, contractName) { + return state.entities.contracts.find((contract => contract.name === contractName)); +} + +export function getContractProfile(state, contractName) { + return state.entities.contractProfiles.find((contractProfile => contractProfile.name === contractName)); +} diff --git a/embark-ui/src/reducers/transactionsReducer.js b/embark-ui/src/reducers/transactionsReducer.js deleted file mode 100644 index 23b353ffa..000000000 --- a/embark-ui/src/reducers/transactionsReducer.js +++ /dev/null @@ -1,36 +0,0 @@ -import * as actions from "../actions"; - -const BN_FACTOR = 10000; - -function sortTransaction(a, b) { - return ((BN_FACTOR * b.blockNumber) + b.transactionIndex) - ((BN_FACTOR * a.blockNumber) + a.transactionIndex); -} - -function filterTransaction(tx, index, self) { - return index === self.findIndex((t) => ( - t.blockNumber === tx.blockNumber && t.transactionIndex === tx.transactionIndex - )); -} - -export default function transactions(state = {}, action) { - switch (action.type) { - case actions.TRANSACTIONS[actions.SUCCESS]: - return { - ...state, error: null, data: [...action.transactions.data, ...state.data || []] - .filter(filterTransaction) - .sort(sortTransaction) - }; - case actions.TRANSACTIONS[actions.FAILURE]: - return Object.assign({}, state, {error: action.error}); - case actions.TRANSACTION[actions.SUCCESS]: - return { - ...state, error: null, data: [action.transaction.data, ...state.data || []] - .filter(filterTransaction) - .sort(sortTransaction) - }; - case actions.TRANSACTION[actions.FAILURE]: - 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 04ad9d181..70a4f1455 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -3,12 +3,13 @@ import * as api from '../api'; import {eventChannel} from 'redux-saga'; import {all, call, fork, put, takeEvery, take} from 'redux-saga/effects'; -const {account, accounts, block, blocks, transaction, transactions, processes, commands} = actions; +const {account, accounts, block, blocks, transaction, transactions, processes, commands, processLogs, + contracts, contract, contractProfile} = actions; function *doRequest(entity, apiFn, payload) { const {response, error} = yield call(apiFn, payload); if(response) { - yield put(entity.success(response)); + yield put(entity.success(response.data, payload)); } else if (error) { yield put(entity.failure(error)); } @@ -22,6 +23,10 @@ export const fetchBlocks = doRequest.bind(null, blocks, api.fetchBlocks); export const fetchTransactions = doRequest.bind(null, transactions, api.fetchTransactions); export const fetchProcesses = doRequest.bind(null, processes, api.fetchProcesses); export const postCommand = doRequest.bind(null, commands, api.postCommand); +export const fetchProcessLogs = doRequest.bind(null, processLogs, api.fetchProcessLogs); +export const fetchContracts = doRequest.bind(null, contracts, api.fetchContracts); +export const fetchContract = doRequest.bind(null, contract, api.fetchContract); +export const fetchContractProfile = doRequest.bind(null, contractProfile, api.fetchContractProfile); export function *watchFetchTransaction() { yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction); @@ -55,17 +60,20 @@ export function *watchPostCommand() { yield takeEvery(actions.COMMANDS[actions.REQUEST], postCommand); } -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.PROCESS_LOGS[actions.REQUEST], fetchProcessLogs); } -export function *watchFetchProcessLogs() { - yield takeEvery(actions.FETCH_PROCESS_LOGS, fetchProcessLogs); +export function *watchFetchContract() { + yield takeEvery(actions.CONTRACT[actions.REQUEST], fetchContract); +} + +export function *watchFetchContracts() { + yield takeEvery(actions.CONTRACTS[actions.REQUEST], fetchContracts); +} + +export function *watchFetchContractProfile() { + yield takeEvery(actions.CONTRACT_PROFILE[actions.REQUEST], fetchContractProfile); } function createChannel(socket) { @@ -97,8 +105,8 @@ export function *listenToProcessLogs(action) { 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}); + const processLog = yield take(channel); + yield put(processLogs.success([processLog])); } } @@ -106,45 +114,6 @@ export function *watchListenToProcessLogs() { yield takeEvery(actions.WATCH_NEW_PROCESS_LOGS, listenToProcessLogs); } -export function *fetchContract(action) { - try { - const contract = yield call(api.fetchContract, action.contractName); - yield put(actions.receiveContract(contract)); - } catch (e) { - yield put(actions.receiveContractError()); - } -} - -export function *watchFetchContract() { - yield takeEvery(actions.FETCH_CONTRACT, fetchContract); -} - -export function *fetchContracts() { - try { - const contracts = yield call(api.fetchContracts); - yield put(actions.receiveContracts(contracts)); - } catch (e) { - yield put(actions.receiveContractsError()); - } -} - -export function *watchFetchContracts() { - yield takeEvery(actions.FETCH_CONTRACTS, fetchContracts); -} - -export function *fetchContractProfile(action) { - try { - const profile = yield call(api.fetchContractProfile, action.contractName); - yield put(actions.receiveContractProfile(profile)); - } catch (e) { - yield put(actions.receiveContractError()); - } -} - -export function *watchFetchContractProfile() { - yield takeEvery(actions.FETCH_CONTRACT_PROFILE, fetchContractProfile); -} - export default function *root() { yield all([ fork(watchInitBlockHeader), diff --git a/lib/core/processes/processLauncher.js b/lib/core/processes/processLauncher.js index 15da00788..a5e6417a0 100644 --- a/lib/core/processes/processLauncher.js +++ b/lib/core/processes/processLauncher.js @@ -73,8 +73,8 @@ class ProcessLauncher { 'ws', apiRoute, (ws, _req) => { - self.events.on('process-log-' + self.name, function(logLevel, msg) { - ws.send(JSON.stringify({msg, msg_clear: msg.stripColors, logLevel}), () => {}); + self.events.on('process-log-' + self.name, function(logLevel, msg, name, timestamp) { + ws.send(JSON.stringify({msg, msg_clear: msg.stripColors, logLevel, name, timestamp}), () => {}); }); } ); @@ -89,8 +89,9 @@ class ProcessLauncher { // Translates logs from the child process to the logger _handleLog(msg) { - 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}); + const timestamp = new Date().getTime(); + this.events.emit('process-log-' + this.name, msg.type, msg.message, this.name, timestamp); + this.logs.push({msg: msg.message, msg_clear: msg.message.stripColors, logLevel: msg.logLevel, name: this.name, timestamp}); if (this.silent && msg.type !== 'error') { return; } diff --git a/lib/core/processes/processManager.js b/lib/core/processes/processManager.js index 7cfee6394..da71e222b 100644 --- a/lib/core/processes/processManager.js +++ b/lib/core/processes/processManager.js @@ -17,13 +17,11 @@ class ProcessManager { 'get', '/embark-api/processes', (req, res) => { - let parsedProcesses = {}; - Object.keys(self.processes).forEach(processName => { - parsedProcesses[processName] = { - state: self.processes[processName].state - }; - }); - res.send(parsedProcesses); + const formatter = (acc, processName) => { + acc.push({state: self.processes[processName].state, name: processName}); + return acc; + }; + res.send(Object.keys(self.processes).reduce(formatter, [])); } ); }