Add plugins and versions to backend tab
This commit is contained in:
parent
950f285d2e
commit
83d6130259
|
@ -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');
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 = () => (
|
|||
<Page.Title className="my-5">Explorer</Page.Title>
|
||||
<div>
|
||||
<List.Group transparent={true}>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/accounts"
|
||||
icon="users"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Accounts
|
||||
</List.GroupItem>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/blocks"
|
||||
icon="book-open"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Blocks
|
||||
</List.GroupItem>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/transactions"
|
||||
icon="activity"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Transactions
|
||||
</List.GroupItem>
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to="/embark/explorer/communication"
|
||||
icon="phone-call"
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
Communication
|
||||
</List.GroupItem>
|
||||
{groupItems.map((groupItem) => (
|
||||
<List.GroupItem
|
||||
className={className}
|
||||
to={groupItem.to}
|
||||
icon={groupItem.icon}
|
||||
RootComponent={withRouter(NavLink)}
|
||||
>
|
||||
{groupItem.value}
|
||||
</List.GroupItem>
|
||||
))}
|
||||
</List.Group>
|
||||
</div>
|
||||
</Grid.Col>
|
||||
|
@ -63,9 +50,10 @@ const ExplorerLayout = () => (
|
|||
<Route exact path="/embark/explorer/accounts/:address" component={AccountContainer} />
|
||||
<Route exact path="/embark/explorer/blocks" component={BlocksContainer} />
|
||||
<Route exact path="/embark/explorer/blocks/:blockNumber" component={BlockContainer} />
|
||||
<Route exact path="/embark/explorer/communication" component={CommunicationContainer} />
|
||||
<Route exact path="/embark/explorer/transactions" component={TransactionsContainer} />
|
||||
<Route exact path="/embark/explorer/transactions/:hash" component={TransactionContainer} />
|
||||
<Route exact path="/embark/explorer/communication" component={CommunicationContainer} />
|
||||
<Route exact path="/embark/explorer/ens" component={ENSContainer} />
|
||||
</Switch>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = <Alert type="warning">The node uses an unsupported version of Whisper</Alert>;
|
||||
}
|
||||
|
||||
if (!this.props.messages) {
|
||||
return <Loading/>;
|
||||
}
|
||||
return (
|
||||
<Page.Content title="Communication explorer">
|
||||
{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);
|
||||
|
||||
|
|
|
@ -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 =
|
||||
<Alert bsStyle="secondary "><Loader/> Checking Whisper support, please wait</Alert>;
|
||||
} else if (!this.props.messageVersion) {
|
||||
isEnabledMessage = <Alert type="warning">The node you are using does not support Whisper</Alert>;
|
||||
} else if (this.props.messageVersion === -1) {
|
||||
isEnabledMessage = <Alert type="warning">The node uses an unsupported version of Whisper</Alert>;
|
||||
}
|
||||
|
||||
if (!this.props.messages) {
|
||||
return <Loading/>;
|
||||
}
|
||||
return (
|
||||
<Page.Content title="Communication explorer">
|
||||
{isEnabledMessage}
|
||||
<Communication listenToMessages={(channel) => this.listenToChannel(channel)}
|
||||
sendMessage={(channel, message) => this.sendMessage(channel, message)}
|
||||
channels={this.props.messages}
|
||||
subscriptions={this.props.messageChannels}/>
|
||||
</Page.Content>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue