From b638b746de7b13694677c469d01d7e6846318877 Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Fri, 1 Dec 2017 08:09:51 -0800 Subject: [PATCH] Custom Nodes - Final Touches (#501) * Add warning about matching nodes, only allow one url:port combination of nodes. * Fix up alert styling. * Custom network form. * Add custom network to redux store. Setup infrastructure for removal and display. * Persist custom networks to LS, show them in display. * Force chain id, make typing happy. * Display custom networks in network dropdown. * Fix form validation, purge unused custom networks. --- common/actions/config/actionCreators.ts | 22 ++- common/actions/config/actionTypes.ts | 16 +- common/actions/config/constants.ts | 2 + .../Header/components/CustomNodeModal.tsx | 163 ++++++++++++++++-- common/components/Header/index.tsx | 48 ++++-- common/config/data.ts | 6 + common/containers/TabSection/index.tsx | 53 ++++-- .../Tabs/Contracts/components/withTx.tsx | 27 +-- common/libs/transaction.ts | 2 +- common/reducers/config.ts | 49 +++++- common/sagas/config.ts | 20 +++ common/sass/styles/overrides/alerts.scss | 22 ++- common/sass/styles/overrides/forms.scss | 6 + common/selectors/config.ts | 21 ++- common/selectors/wallet.ts | 3 +- common/store.ts | 3 +- common/utils/network.ts | 30 ++++ 17 files changed, 406 insertions(+), 87 deletions(-) create mode 100644 common/utils/network.ts diff --git a/common/actions/config/actionCreators.ts b/common/actions/config/actionCreators.ts index 8b189127..dcfea5c4 100644 --- a/common/actions/config/actionCreators.ts +++ b/common/actions/config/actionCreators.ts @@ -1,6 +1,6 @@ import * as interfaces from './actionTypes'; import { TypeKeys } from './constants'; -import { NodeConfig, CustomNodeConfig } from 'config/data'; +import { NodeConfig, CustomNodeConfig, CustomNetworkConfig } from 'config/data'; export type TForceOfflineConfig = typeof forceOfflineConfig; export function forceOfflineConfig(): interfaces.ForceOfflineAction { @@ -80,6 +80,26 @@ export function removeCustomNode( }; } +export type TAddCustomNetwork = typeof addCustomNetwork; +export function addCustomNetwork( + payload: CustomNetworkConfig +): interfaces.AddCustomNetworkAction { + return { + type: TypeKeys.CONFIG_ADD_CUSTOM_NETWORK, + payload + }; +} + +export type TRemoveCustomNetwork = typeof removeCustomNetwork; +export function removeCustomNetwork( + payload: CustomNetworkConfig +): interfaces.RemoveCustomNetworkAction { + return { + type: TypeKeys.CONFIG_REMOVE_CUSTOM_NETWORK, + payload + }; +} + export type TSetLatestBlock = typeof setLatestBlock; export function setLatestBlock( payload: string diff --git a/common/actions/config/actionTypes.ts b/common/actions/config/actionTypes.ts index e8b27135..7e72703d 100644 --- a/common/actions/config/actionTypes.ts +++ b/common/actions/config/actionTypes.ts @@ -1,5 +1,5 @@ import { TypeKeys } from './constants'; -import { CustomNodeConfig, NodeConfig } from 'config/data'; +import { NodeConfig, CustomNodeConfig, CustomNetworkConfig } from 'config/data'; /*** Toggle Offline ***/ export interface ToggleOfflineAction { @@ -56,6 +56,18 @@ export interface RemoveCustomNodeAction { payload: CustomNodeConfig; } +/*** Add Custom Network ***/ +export interface AddCustomNetworkAction { + type: TypeKeys.CONFIG_ADD_CUSTOM_NETWORK; + payload: CustomNetworkConfig; +} + +/*** Remove Custom Network ***/ +export interface RemoveCustomNetworkAction { + type: TypeKeys.CONFIG_REMOVE_CUSTOM_NETWORK; + payload: CustomNetworkConfig; +} + /*** Set Latest Block ***/ export interface SetLatestBlockAction { type: TypeKeys.CONFIG_SET_LATEST_BLOCK; @@ -78,5 +90,7 @@ export type ConfigAction = | ChangeNodeIntentAction | AddCustomNodeAction | RemoveCustomNodeAction + | AddCustomNetworkAction + | RemoveCustomNetworkAction | SetLatestBlockAction | Web3UnsetNodeAction; diff --git a/common/actions/config/constants.ts b/common/actions/config/constants.ts index d11471ac..519f2ba6 100644 --- a/common/actions/config/constants.ts +++ b/common/actions/config/constants.ts @@ -8,6 +8,8 @@ export enum TypeKeys { CONFIG_POLL_OFFLINE_STATUS = 'CONFIG_POLL_OFFLINE_STATUS', CONFIG_ADD_CUSTOM_NODE = 'CONFIG_ADD_CUSTOM_NODE', CONFIG_REMOVE_CUSTOM_NODE = 'CONFIG_REMOVE_CUSTOM_NODE', + CONFIG_ADD_CUSTOM_NETWORK = 'CONFIG_ADD_CUSTOM_NETWORK', + CONFIG_REMOVE_CUSTOM_NETWORK = 'CONFIG_REMOVE_CUSTOM_NETWORK', CONFIG_SET_LATEST_BLOCK = 'CONFIG_SET_LATEST_BLOCK', CONFIG_NODE_WEB3_UNSET = 'CONFIG_NODE_WEB3_UNSET' } diff --git a/common/components/Header/components/CustomNodeModal.tsx b/common/components/Header/components/CustomNodeModal.tsx index fae273eb..ac58e895 100644 --- a/common/components/Header/components/CustomNodeModal.tsx +++ b/common/components/Header/components/CustomNodeModal.tsx @@ -2,9 +2,12 @@ import React from 'react'; import classnames from 'classnames'; import Modal, { IButton } from 'components/ui/Modal'; import translate from 'translations'; -import { NETWORKS, CustomNodeConfig } from 'config/data'; +import { NETWORKS, CustomNodeConfig, CustomNetworkConfig } from 'config/data'; +import { makeCustomNodeId } from 'utils/node'; +import { makeCustomNetworkId } from 'utils/network'; const NETWORK_KEYS = Object.keys(NETWORKS); +const CUSTOM = 'custom'; interface Input { name: string; @@ -13,7 +16,10 @@ interface Input { } interface Props { + customNodes: CustomNodeConfig[]; + customNetworks: CustomNetworkConfig[]; handleAddCustomNode(node: CustomNodeConfig): void; + handleAddCustomNetwork(node: CustomNetworkConfig): void; handleClose(): void; } @@ -22,6 +28,9 @@ interface State { url: string; port: string; network: string; + customNetworkName: string; + customNetworkUnit: string; + customNetworkChainId: string; hasAuth: boolean; username: string; password: string; @@ -33,13 +42,17 @@ export default class CustomNodeModal extends React.Component { url: '', port: '', network: NETWORK_KEYS[0], + customNetworkName: '', + customNetworkUnit: '', + customNetworkChainId: '', hasAuth: false, username: '', password: '' }; public render() { - const { handleClose } = this.props; + const { customNetworks, handleClose } = this.props; + const { network } = this.state; const isHttps = window.location.protocol.includes('https'); const invalids = this.getInvalids(); @@ -56,6 +69,8 @@ export default class CustomNodeModal extends React.Component { } ]; + const conflictedNode = this.getConflictedNode(); + return ( { >
{isHttps && ( -
+
{translate('NODE_Warning')}
)} + {conflictedNode && ( +
+ You already have a node called '{conflictedNode.name}' that + matches this one, saving this will overwrite it +
+ )} +
@@ -87,7 +109,7 @@ export default class CustomNodeModal extends React.Component {
+ {network === CUSTOM && ( +
+
+ + {this.renderInput( + { + name: 'customNetworkName', + placeholder: 'My Custom Network' + }, + invalids + )} +
+
+ + {this.renderInput( + { + name: 'customNetworkUnit', + placeholder: 'ETH' + }, + invalids + )} +
+
+ + {this.renderInput( + { + name: 'customNetworkChainId', + placeholder: 'e.g. 1' + }, + invalids + )} +
+
+ )} + +
+
@@ -123,6 +191,7 @@ export default class CustomNodeModal extends React.Component { )}
+