diff --git a/embark-ui/src/actions/index.js b/embark-ui/src/actions/index.js index 61606f13..1424cfb2 100644 --- a/embark-ui/src/actions/index.js +++ b/embark-ui/src/actions/index.js @@ -104,11 +104,18 @@ export const contractProfile = { failure: (error) => action(CONTRACT_PROFILE[FAILURE], {error}) }; -export const MESSAGE_VERSION = createRequestTypes('MESSAGE_VERSION'); -export const messageVersion = { - request: () => action(MESSAGE_VERSION[REQUEST]), - success: (messageVersion) => action(MESSAGE_VERSION[SUCCESS], {messageVersion}), - failure: (error) => action(MESSAGE_VERSION[FAILURE], {error}) +export const VERSIONS = createRequestTypes('VERSIONS'); +export const versions = { + request: () => action(VERSIONS[REQUEST]), + success: (versions) => action(VERSIONS[SUCCESS], {versions}), + failure: (error) => action(VERSIONS[FAILURE], {error}) +}; + +export const PLUGINS = createRequestTypes('PLUGINS'); +export const plugins = { + request: () => action(PLUGINS[REQUEST]), + success: (plugins) => action(PLUGINS[SUCCESS], {plugins}), + failure: (error) => action(PLUGINS[FAILURE], {error}) }; export const MESSAGE_SEND = createRequestTypes('MESSAGE_SEND'); diff --git a/embark-ui/src/api/index.js b/embark-ui/src/api/index.js index d2a17e75..4dc9dc2d 100644 --- a/embark-ui/src/api/index.js +++ b/embark-ui/src/api/index.js @@ -68,8 +68,12 @@ export function fetchContract(payload) { return get(`/contract/${payload.contractName}`); } -export function communicationVersion() { - return get(`/communication/version`); +export function fetchVersions() { + return get('/versions'); +} + +export function fetchPlugins() { + return get('/plugins'); } export function sendMessage(payload) { diff --git a/embark-ui/src/components/ExplorerLayout.js b/embark-ui/src/components/ExplorerLayout.js index e98f7586..0ad2a318 100644 --- a/embark-ui/src/components/ExplorerLayout.js +++ b/embark-ui/src/components/ExplorerLayout.js @@ -10,9 +10,18 @@ import AccountsContainer from '../containers/AccountsContainer'; import AccountContainer from '../containers/AccountContainer'; import BlocksContainer from '../containers/BlocksContainer'; import BlockContainer from '../containers/BlockContainer'; -import CommunicationContainer from '../containers/CommunicationContainer'; import TransactionsContainer from '../containers/TransactionsContainer'; import TransactionContainer from '../containers/TransactionContainer'; +import CommunicationContainer from '../containers/CommunicationContainer'; +import ENSContainer from '../containers/ENSContainer'; + +const groupItems = [ + {to: "/embark/explorer/accounts", icon: "users", value: "Accounts"}, + {to: "/embark/explorer/blocks", icon: "book-open", value: "Blocks"}, + {to: "/embark/explorer/transactions", icon: "activity", value: "Transactions"}, + {to: "/embark/explorer/communication", icon: "phone-call", value: "Communication"}, + {to: "/embark/explorer/ens", icon: "disc", value: "ENS"} +]; const className = "d-flex align-items-center"; @@ -22,38 +31,16 @@ const ExplorerLayout = () => ( Explorer
- - Accounts - - - Blocks - - - Transactions - - - Communication - + {groupItems.map((groupItem) => ( + + {groupItem.value} + + ))}
@@ -63,9 +50,10 @@ const ExplorerLayout = () => ( - + + diff --git a/embark-ui/src/containers/AppContainer.js b/embark-ui/src/containers/AppContainer.js index 47a47d9d..5f1e7317 100644 --- a/embark-ui/src/containers/AppContainer.js +++ b/embark-ui/src/containers/AppContainer.js @@ -6,13 +6,22 @@ import React, {Component} from 'react'; import history from '../history'; import Layout from '../components/Layout'; import routes from '../routes'; -import {contracts as contractsAction, initBlockHeader, processes as processesAction} from '../actions'; + +import { + initBlockHeader, + contracts as contractsAction, + processes as processesAction, + versions as versionsAction, + plugins as pluginsAction +} from '../actions'; class AppContainer extends Component { componentDidMount() { this.props.initBlockHeader(); this.props.fetchProcesses(); this.props.fetchContracts(); + this.props.fetchVersions(); + this.props.fetchPlugins(); } render() { @@ -29,7 +38,9 @@ class AppContainer extends Component { AppContainer.propTypes = { initBlockHeader: PropTypes.func, fetchContracts: PropTypes.func, - fetchProcesses: PropTypes.func + fetchProcesses: PropTypes.func, + fetchPlugins: PropTypes.func, + fetchVersions: PropTypes.func }; export default connect( @@ -37,6 +48,8 @@ export default connect( { initBlockHeader, fetchProcesses: processesAction.request, - fetchContracts: contractsAction.request + fetchContracts: contractsAction.request, + fetchVersions: versionsAction.request, + fetchPlugins: pluginsAction.request }, )(AppContainer); diff --git a/embark-ui/src/containers/CommunicationContainer.js b/embark-ui/src/containers/CommunicationContainer.js index 389c23dc..57a125cf 100644 --- a/embark-ui/src/containers/CommunicationContainer.js +++ b/embark-ui/src/containers/CommunicationContainer.js @@ -2,16 +2,11 @@ import PropTypes from "prop-types"; import React, {Component} from 'react'; import connect from "react-redux/es/connect/connect"; import {Alert, Loader, Page} from 'tabler-react'; -import {messageSend, messageListen, messageVersion} from "../actions"; +import {messageSend, messageListen} from "../actions"; import Communication from "../components/Communication"; -import Loading from "../components/Loading"; -import {getMessageVersion, getMessages, getMessageChannels} from "../reducers/selectors"; +import {getMessages, getMessageChannels} from "../reducers/selectors"; class CommunicationContainer extends Component { - componentDidMount() { - this.props.communicationVersion(); - } - sendMessage(topic, message) { this.props.messageSend({topic, message}); } @@ -31,9 +26,6 @@ class CommunicationContainer extends Component { isEnabledMessage = The node uses an unsupported version of Whisper; } - if (!this.props.messages) { - return ; - } return ( {isEnabledMessage} @@ -49,8 +41,7 @@ class CommunicationContainer extends Component { CommunicationContainer.propTypes = { messageSend: PropTypes.func, messageListen: PropTypes.func, - communicationVersion: PropTypes.func, - messageVersion: PropTypes.number, + isWhisperEnabled: PropTypes.bool, messages: PropTypes.object, messageChannels: PropTypes.array }; @@ -59,7 +50,7 @@ function mapStateToProps(state) { return { messages: getMessages(state), messageChannels: getMessageChannels(state), - messageVersion: getMessageVersion(state) + isWhisperEnabled: isWhisperEnabled(state) }; } @@ -68,7 +59,6 @@ export default connect( { messageSend: messageSend.request, messageListen: messageListen.request, - communicationVersion: messageVersion.request } )(CommunicationContainer); diff --git a/embark-ui/src/containers/ENSContainer.js b/embark-ui/src/containers/ENSContainer.js new file mode 100644 index 00000000..da118914 --- /dev/null +++ b/embark-ui/src/containers/ENSContainer.js @@ -0,0 +1,67 @@ +import PropTypes from "prop-types"; +import React, {Component} from 'react'; +import connect from "react-redux/es/connect/connect"; +import {Alert, Loader, Page} from 'tabler-react'; +import {messageSend, messageListen, messageVersion} from "../actions"; +import Communication from "../components/Communication"; +import Loading from "../components/Loading"; +import {getMessages, getMessageChannels} from "../reducers/selectors"; + +class CommunicationContainer extends Component { + sendMessage(topic, message) { + this.props.messageSend({topic, message}); + } + + listenToChannel(channel) { + this.props.messageListen(channel); + } + + render() { + let isEnabledMessage = ''; + if (this.props.messageVersion === undefined || this.props.messageVersion === null) { + isEnabledMessage = + Checking Whisper support, please wait; + } else if (!this.props.messageVersion) { + isEnabledMessage = The node you are using does not support Whisper; + } else if (this.props.messageVersion === -1) { + isEnabledMessage = The node uses an unsupported version of Whisper; + } + + if (!this.props.messages) { + return ; + } + return ( + + {isEnabledMessage} + this.listenToChannel(channel)} + sendMessage={(channel, message) => this.sendMessage(channel, message)} + channels={this.props.messages} + subscriptions={this.props.messageChannels}/> + + ); + } +} + +CommunicationContainer.propTypes = { + messageSend: PropTypes.func, + messageListen: PropTypes.func, + messageVersion: PropTypes.number, + messages: PropTypes.object, + messageChannels: PropTypes.array +}; + +function mapStateToProps(state) { + return { + messages: getMessages(state), + messageChannels: getMessageChannels(state) + }; +} + +export default connect( + mapStateToProps, + { + messageSend: messageSend.request, + messageListen: messageListen.request + } +)(CommunicationContainer); + diff --git a/embark-ui/src/reducers/index.js b/embark-ui/src/reducers/index.js index 2e7ca707..315ce094 100644 --- a/embark-ui/src/reducers/index.js +++ b/embark-ui/src/reducers/index.js @@ -15,8 +15,9 @@ const entitiesDefaultState = { commands: [], messages: [], messageChannels: [], - messageVersion: null, - fiddle: null + fiddle: null, + versions: [], + plugins: [] }; const sorter = { @@ -61,10 +62,7 @@ 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] && !Array.isArray(action[name])) { - return {...state, [name]: action[name]}; - } - if (action[name] && (!Array.isArray(action[name]) || action[name].length > 1)) { + 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) { diff --git a/embark-ui/src/sagas/index.js b/embark-ui/src/sagas/index.js index 78a0e0e0..74b0348b 100644 --- a/embark-ui/src/sagas/index.js +++ b/embark-ui/src/sagas/index.js @@ -4,8 +4,7 @@ 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, processLogs, - contracts, contract, contractProfile, messageSend, messageVersion, messageListen, contractLogs, - fiddle} = actions; + contracts, contract, contractProfile, messageSend, versions, plugins, messageListen, fiddle} = actions; function *doRequest(entity, apiFn, payload) { const {response, error} = yield call(apiFn, payload); @@ -16,6 +15,8 @@ function *doRequest(entity, apiFn, payload) { } } +export const fetchPlugins = doRequest.bind(null, plugins, api.fetchPlugins); +export const fetchVersions = doRequest.bind(null, versions, api.fetchVersions); export const fetchAccount = doRequest.bind(null, account, api.fetchAccount); export const fetchBlock = doRequest.bind(null, block, api.fetchBlock); export const fetchTransaction = doRequest.bind(null, transaction, api.fetchTransaction); @@ -30,6 +31,7 @@ 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 const fetchFiddle = doRequest.bind(null, fiddle, api.fetchFiddle); +export const sendMessage = doRequest.bind(null, messageSend, api.sendMessage); export function *watchFetchTransaction() { yield takeEvery(actions.TRANSACTION[actions.REQUEST], fetchTransaction); @@ -83,6 +85,18 @@ export function *watchFetchContractProfile() { yield takeEvery(actions.CONTRACT_PROFILE[actions.REQUEST], fetchContractProfile); } +export function *watchFetchVersions() { + yield takeEvery(actions.VERSIONS[actions.REQUEST], fetchVersions); +} + +export function *watchFetchPlugins() { + yield takeEvery(actions.PLUGINS[actions.REQUEST], fetchPlugins); +} + +export function *watchSendMessage() { + yield takeEvery(actions.MESSAGE_SEND[actions.REQUEST], sendMessage); +} + function createChannel(socket) { return eventChannel(emit => { socket.onmessage = ((message) => { @@ -134,8 +148,6 @@ export function *watchListenToContractLogs() { yield takeEvery(actions.WATCH_NEW_CONTRACT_LOGS, listenToContractLogs); } -export const sendMessage = doRequest.bind(null, messageSend, api.sendMessage); - export function *watchSendMessage() { yield takeEvery(actions.MESSAGE_SEND[actions.REQUEST], sendMessage); } @@ -153,16 +165,11 @@ export function *watchListenToMessages() { yield takeEvery(actions.MESSAGE_LISTEN[actions.REQUEST], listenToMessages); } -export const fetchCommunicationVersion = doRequest.bind(null, messageVersion, api.communicationVersion); - -export function *watchCommunicationVersion() { - yield takeEvery(actions.MESSAGE_VERSION[actions.REQUEST], fetchCommunicationVersion); -} - export function *watchFetchFiddle() { yield takeEvery(actions.FIDDLE[actions.REQUEST], fetchFiddle); } + export default function *root() { yield all([ fork(watchInitBlockHeader), @@ -176,7 +183,8 @@ export default function *root() { fork(watchFetchBlock), fork(watchFetchTransactions), fork(watchPostCommand), - fork(watchCommunicationVersion), + fork(watchFetchVersions), + fork(watchFetchPlugins), fork(watchFetchBlocks), fork(watchFetchContracts), fork(watchListenToMessages), @@ -187,4 +195,3 @@ export default function *root() { fork(watchFetchFiddle) ]); } - diff --git a/lib/core/plugins.js b/lib/core/plugins.js index de7bc2ea..5df5bccb 100644 --- a/lib/core/plugins.js +++ b/lib/core/plugins.js @@ -15,21 +15,19 @@ var Plugins = function(options) { }; Plugins.prototype.loadPlugins = function() { - var pluginConfig; - for (var pluginName in this.pluginList) { - pluginConfig = this.pluginList[pluginName]; + for (let pluginName in this.pluginList) { + let pluginConfig = this.pluginList[pluginName]; this.loadPlugin(pluginName, pluginConfig); } }; Plugins.prototype.listPlugins = function() { - const list = []; - this.plugins.forEach(plugin => { + return this.plugins.reduce((list, plugin) => { if (plugin.loaded) { list.push(plugin.name); } - }); - return list; + return list; + }, []); }; // for services that act as a plugin but have core functionality diff --git a/lib/modules/library_manager/index.js b/lib/modules/library_manager/index.js index 032d643e..a366e97d 100644 --- a/lib/modules/library_manager/index.js +++ b/lib/modules/library_manager/index.js @@ -11,6 +11,7 @@ class LibraryManager { this.determineVersions(); this.registerCommands(); + this.registerAPICommands(); this.listenToCommandsToGetVersions(); this.listenToCommandsToGetLibrary(); } @@ -51,6 +52,18 @@ class LibraryManager { }); } + registerAPICommands() { + const self = this; + self.embark.registerAPICall( + 'get', + '/embark-api/versions', + (req, res) => { + const versions = Object.keys(self.versions).map((name) => ({value: self.versions[name], name})); + res.send(versions); + } + ); + } + listenToCommandsToGetVersions() { const self = this; for (let libName in this.versions) { diff --git a/lib/modules/webserver/server.js b/lib/modules/webserver/server.js index 07f1a919..94001961 100644 --- a/lib/modules/webserver/server.js +++ b/lib/modules/webserver/server.js @@ -85,6 +85,13 @@ class Server { if (self.plugins) { let apiCalls = self.plugins.getPluginsProperty("apiCalls", "apiCalls"); + + app.get('/embark-api/plugins', function(req, res) { + res.send(JSON.stringify(self.plugins.plugins.map((plugin) => { + return {name: plugin.name}; + }))); + }); + for (let apiCall of apiCalls) { console.dir("adding " + apiCall.method + " " + apiCall.endpoint); app[apiCall.method].apply(app, [apiCall.endpoint, apiCall.cb]); diff --git a/lib/modules/whisper/index.js b/lib/modules/whisper/index.js index 394b6cee..4baafa3c 100644 --- a/lib/modules/whisper/index.js +++ b/lib/modules/whisper/index.js @@ -199,14 +199,6 @@ class Whisper { ws.send(JSON.stringify(result)); }); }); - - self.embark.registerAPICall( - 'get', - '/embark-api/communication/version', - (req, res) => { - res.send(self.isOldWeb3 ? -1 : self.version || 0); - } - ); }); } }