From b48617e95e983c3a8e1b568d6e2178fde37fb8c8 Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Sat, 24 Feb 2018 13:02:07 -0500 Subject: [PATCH] Simplify custom node URL (#1141) * Simplify custom nodes to just be a URL, not a url + port. * Allow modals to specify max width (#1142) --- .../Header/components/CustomNodeModal.tsx | 53 ++++++------------- common/components/Header/index.tsx | 8 +-- common/components/ui/Modal.scss | 2 +- common/components/ui/Modal.tsx | 17 ++++-- common/selectors/config/nodes.ts | 30 +++++++---- shared/types/node.d.ts | 1 - .../reducers/config/nodes/customNodes.spec.ts | 1 - 7 files changed, 55 insertions(+), 57 deletions(-) diff --git a/common/components/Header/components/CustomNodeModal.tsx b/common/components/Header/components/CustomNodeModal.tsx index 2df65db1..1160a756 100644 --- a/common/components/Header/components/CustomNodeModal.tsx +++ b/common/components/Header/components/CustomNodeModal.tsx @@ -20,6 +20,9 @@ interface Input { name: string; placeholder?: string; type?: string; + autoComplete?: 'off'; + onFocus?(): void; + onBlur?(): void; } interface OwnProps { @@ -40,7 +43,6 @@ interface StateProps { interface State { name: string; url: string; - port: string; network: string; customNetworkId: string; customNetworkUnit: string; @@ -56,7 +58,6 @@ class CustomNodeModal extends React.Component { public state: State = { name: '', url: '', - port: '', network: Object.keys(this.props.staticNetworks)[0], customNetworkId: '', customNetworkUnit: '', @@ -94,6 +95,7 @@ class CustomNodeModal extends React.Component { isOpen={true} buttons={buttons} handleClose={handleClose} + maxWidth={580} >
{isHttps &&
{translate('NODE_Warning')}
} @@ -175,27 +177,14 @@ class CustomNodeModal extends React.Component {
)} -
-
-
+
{this.renderInput( { name: 'url', - placeholder: 'https://127.0.0.1/' - }, - invalids - )} -
- -
- - {this.renderInput( - { - name: 'port', - placeholder: '8545', - type: 'number' + placeholder: 'e.g. https://127.0.0.1:8545/', + autoComplete: 'off' }, invalids )} @@ -248,6 +237,7 @@ class CustomNodeModal extends React.Component { })} value={this.state[input.name]} onChange={this.handleChange} + autoComplete="off" {...input} /> ); @@ -256,7 +246,6 @@ class CustomNodeModal extends React.Component { private getInvalids(): { [key: string]: boolean } { const { url, - port, hasAuth, username, password, @@ -265,7 +254,7 @@ class CustomNodeModal extends React.Component { customNetworkUnit, customNetworkChainId } = this.state; - const required: (keyof State)[] = ['name', 'url', 'port', 'network']; + const required: (keyof State)[] = ['name', 'url', 'network']; const invalids: { [key: string]: boolean } = {}; // Required fields @@ -275,17 +264,12 @@ class CustomNodeModal extends React.Component { } }); - // Somewhat valid URL, not 100% fool-proof - if (!/https?\:\/\/\w+/i.test(url)) { + // Parse the URL, and make sure what they typed isn't parsed as relative. + // Not a perfect regex, just checks for protocol + any char + if (!/^https?:\/\/.+/i.test(url)) { invalids.url = true; } - // Numeric port within range - const iport = parseInt(port, 10); - if (!iport || iport < 1 || iport > 65535) { - invalids.port = true; - } - // If they have auth, make sure it's provided if (hasAuth) { if (!username) { @@ -331,28 +315,25 @@ class CustomNodeModal extends React.Component { } private makeCustomNodeConfigFromState(): CustomNodeConfig { - const { network } = this.state; + const { network, url, name, username, password } = this.state; const networkId = network === CUSTOM ? this.makeCustomNetworkId(this.makeCustomNetworkConfigFromState()) : network; - const port = parseInt(this.state.port, 10); - const url = this.state.url.trim(); const node: Omit = { isCustom: true, service: 'your custom node', - id: `${url}:${port}`, - name: this.state.name.trim(), + id: url, + name: name.trim(), url, - port, network: networkId, ...(this.state.hasAuth ? { auth: { - username: this.state.username, - password: this.state.password + username, + password } } : {}) diff --git a/common/components/Header/index.tsx b/common/components/Header/index.tsx index 23ce24b7..d0884ce3 100644 --- a/common/components/Header/index.tsx +++ b/common/components/Header/index.tsx @@ -103,23 +103,23 @@ class Header extends Component { const LanguageDropDown = Dropdown as new () => Dropdown; const options = nodeOptions.map(n => { if (n.isCustom) { - const { name: { networkId, nodeId }, isCustom, id, ...rest } = n; + const { label, isCustom, id, ...rest } = n; return { ...rest, name: ( - {networkId} - {nodeId} (custom) + {label.network} - {label.nodeName} (custom) ), onRemove: () => this.props.removeCustomNode({ id }) }; } else { - const { name: { networkId, service }, isCustom, ...rest } = n; + const { label, isCustom, ...rest } = n; return { ...rest, name: ( - {networkId} ({service}) + {label.network} ({label.service}) ) }; diff --git a/common/components/ui/Modal.scss b/common/components/ui/Modal.scss index d3892aad..fa036cae 100644 --- a/common/components/ui/Modal.scss +++ b/common/components/ui/Modal.scss @@ -111,7 +111,7 @@ $m-anim-speed: 400ms; // Mobile styles @media(max-width: $screen-sm) { - width: calc(100% - 40px); + width: calc(100% - 40px) !important; } } diff --git a/common/components/ui/Modal.tsx b/common/components/ui/Modal.tsx index fd3608f6..dbe3ca5b 100644 --- a/common/components/ui/Modal.tsx +++ b/common/components/ui/Modal.tsx @@ -15,8 +15,13 @@ interface Props { disableButtons?: boolean; children: any; buttons?: IButton[]; + maxWidth?: number; handleClose?(): void; } +interface ModalStyle { + width?: string; + maxWidth?: string; +} const Fade = ({ children, ...props }) => ( @@ -46,16 +51,22 @@ export default class Modal extends PureComponent { } public render() { - const { isOpen, title, children, buttons, handleClose } = this.props; + const { isOpen, title, children, buttons, handleClose, maxWidth } = this.props; const hasButtons = buttons && buttons.length; + const modalStyle: ModalStyle = {}; + + if (maxWidth) { + modalStyle.width = '100%'; + modalStyle.maxWidth = `${maxWidth}px`; + } return ( {isOpen && (
-
-
+
+
{title && (

{title}

diff --git a/common/selectors/config/nodes.ts b/common/selectors/config/nodes.ts index f6e6366b..2b196c6c 100644 --- a/common/selectors/config/nodes.ts +++ b/common/selectors/config/nodes.ts @@ -119,7 +119,7 @@ export function getNodeLib(state: AppState) { export interface NodeOption { isCustom: false; value: string; - name: { networkId?: string; service: string }; + label: { network: string; service: string }; color?: string; hidden?: boolean; } @@ -127,12 +127,14 @@ export interface NodeOption { export function getStaticNodeOptions(state: AppState): NodeOption[] { const staticNetworkConfigs = getStaticNetworkConfigs(state); return Object.entries(getStaticNodes(state)).map(([nodeId, node]: [string, StaticNodeConfig]) => { - const networkId = node.network; - const associatedNetwork = staticNetworkConfigs[networkId]; + const associatedNetwork = staticNetworkConfigs[node.network]; const opt: NodeOption = { isCustom: node.isCustom, value: nodeId, - name: { networkId, service: node.service }, + label: { + network: node.network, + service: node.service + }, color: associatedNetwork.color, hidden: node.hidden }; @@ -144,7 +146,10 @@ export interface CustomNodeOption { isCustom: true; id: string; value: string; - name: { networkId?: string; nodeId: string }; + label: { + network: string; + nodeName: string; + }; color?: string; hidden?: boolean; } @@ -153,15 +158,18 @@ export function getCustomNodeOptions(state: AppState): CustomNodeOption[] { const staticNetworkConfigs = getStaticNetworkConfigs(state); const customNetworkConfigs = getCustomNetworkConfigs(state); return Object.entries(getCustomNodeConfigs(state)).map( - ([nodeId, node]: [string, CustomNodeConfig]) => { - const networkId = node.network; - const associatedNetwork = isStaticNetworkId(state, networkId) - ? staticNetworkConfigs[networkId] - : customNetworkConfigs[networkId]; + ([_, node]: [string, CustomNodeConfig]) => { + const chainId = node.network; + const associatedNetwork = isStaticNetworkId(state, chainId) + ? staticNetworkConfigs[chainId] + : customNetworkConfigs[chainId]; const opt: CustomNodeOption = { isCustom: node.isCustom, value: node.id, - name: { networkId, nodeId }, + label: { + network: associatedNetwork.unit, + nodeName: node.name + }, color: associatedNetwork.isCustom ? undefined : associatedNetwork.color, hidden: false, id: node.id diff --git a/shared/types/node.d.ts b/shared/types/node.d.ts index 6b3618bc..b9676fdd 100644 --- a/shared/types/node.d.ts +++ b/shared/types/node.d.ts @@ -10,7 +10,6 @@ interface CustomNodeConfig { lib: CustomNode; service: 'your custom node'; url: string; - port: number; network: string; auth?: { username: string; diff --git a/spec/reducers/config/nodes/customNodes.spec.ts b/spec/reducers/config/nodes/customNodes.spec.ts index b18f7be1..cf6e9df2 100644 --- a/spec/reducers/config/nodes/customNodes.spec.ts +++ b/spec/reducers/config/nodes/customNodes.spec.ts @@ -9,7 +9,6 @@ const firstCustomNode: CustomNodeConfig = { lib: jest.fn() as any, name: 'My cool custom node', network: 'CustomNetworkId', - port: 8080, service: 'your custom node', url: '127.0.0.1' };