Skip to content

Commit c634d5b

Browse files
committed
feat(neuron-ui): add dynamic validation on the network editor
1 parent 9ff70c9 commit c634d5b

4 files changed

Lines changed: 53 additions & 18 deletions

File tree

packages/neuron-ui/src/components/NetworkEditor/hooks.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,37 +77,54 @@ export const useInitialize = (
7777
}, [dispatch, id, initialize, networks])
7878
}
7979

80-
export const useInputs = (editor: EditorType) => {
80+
export const useInputs = (editor: EditorType, usedNetworkNames: string[], t: any) => {
8181
return useMemo(
8282
() => [
8383
{
8484
...editor.remote,
8585
label: i18n.t('settings.network.edit-network.rpc-url'),
8686
tooltip: TooltipText.URL,
8787
placeholder: PlaceHolder.URL,
88+
onGetErrorMessage: (url: string) => {
89+
if (!url) {
90+
return t('messages.url-required')
91+
}
92+
if (!/^https?:\/\//.test(url)) {
93+
return t('messages.rpc-url-should-have-protocol')
94+
}
95+
if (/\s/.test(url)) {
96+
return t('messages.rpc-url-should-have-no-whitespaces')
97+
}
98+
return ''
99+
},
88100
},
89101
{
90102
...editor.name,
91103
label: i18n.t('settings.network.edit-network.name'),
92104
tooltip: TooltipText.Name,
93105
placeholder: PlaceHolder.Name,
106+
onGetErrorMessage: (name: string) => {
107+
if (!name) {
108+
return t('messages.name-required')
109+
}
110+
if (usedNetworkNames.includes(name)) {
111+
return t('messages.network-name-used')
112+
}
113+
return ''
114+
},
94115
},
95116
],
96-
[editor.remote, editor.name]
117+
[editor.remote, editor.name, usedNetworkNames, t]
97118
)
98119
}
99120

100121
export const useIsInputsValid = (editor: EditorType, cachedNetwork: State.Network | undefined) => {
101-
const invalidParams = useMemo(() => !editor.name.value || !editor.remote.value, [
102-
editor.name.value,
103-
editor.remote.value,
104-
])
105-
122+
const [errors, setErrors] = useState([!cachedNetwork && !editor.name.value, !cachedNetwork && !editor.remote.value])
106123
const notModified = useMemo(
107124
() => cachedNetwork && (cachedNetwork.name === editor.name.value && cachedNetwork.remote === editor.remote.value),
108125
[cachedNetwork, editor.name.value, editor.remote.value]
109126
)
110-
return { invalidParams, notModified }
127+
return { errors, setErrors, notModified }
111128
}
112129

113130
export const useHandleSubmit = (

packages/neuron-ui/src/components/NetworkEditor/index.tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useRef } from 'react'
1+
import React, { useMemo, useRef } from 'react'
22
import { RouteComponentProps } from 'react-router-dom'
33
import { useTranslation } from 'react-i18next'
44
import { Stack, PrimaryButton, DefaultButton, TextField } from 'office-ui-fabric-react'
@@ -17,28 +17,42 @@ const NetworkEditor = ({
1717
}: React.PropsWithoutRef<StateWithDispatch & RouteComponentProps<{ id: string }>>) => {
1818
const editor = useNetworkEditor()
1919
const [t] = useTranslation()
20-
const inputs = useInputs(editor)
20+
const cachedNetworks = useRef(networks)
21+
const cachedNetwork = cachedNetworks.current.find(network => network.id === id)
22+
const usedNetworkNames = useMemo(
23+
() => networks.map(n => n.name).filter(name => name !== ((cachedNetwork && cachedNetwork.name) || '')),
24+
[networks]
25+
)
26+
const inputs = useInputs(editor, usedNetworkNames, t)
2127
const goBack = useGoBack(history)
2228
useInitialize(id, networks, editor.initialize, dispatch)
2329

24-
const cachedNetworks = useRef(networks)
25-
const cachedNetwork = cachedNetworks.current.find(network => network.id === id)
26-
const { invalidParams, notModified } = useIsInputsValid(editor, cachedNetwork)
30+
const { errors, setErrors, notModified } = useIsInputsValid(editor, cachedNetwork)
2731
const handleSubmit = useHandleSubmit(id, editor.name.value, editor.remote.value, networks, history, dispatch)
2832

2933
return (
3034
<Stack tokens={{ childrenGap: 15 }}>
3135
<h1>{t('settings.network.edit-network.title')}</h1>
3236
<Stack tokens={{ childrenGap: 15 }}>
33-
{inputs.map(inputProps => (
37+
{inputs.map((inputProps, idx) => (
3438
<Stack.Item key={inputProps.label}>
35-
<TextField {...inputProps} key={inputProps.label} required />
39+
<TextField
40+
{...inputProps}
41+
key={inputProps.label}
42+
required
43+
validateOnLoad={false}
44+
onNotifyValidationResult={(msg: any) => {
45+
const errs = [...errors]
46+
errs.splice(idx, 1, msg !== '')
47+
setErrors(errs)
48+
}}
49+
/>
3650
</Stack.Item>
3751
))}
3852
</Stack>
3953
<Stack horizontal horizontalAlign="end" tokens={{ childrenGap: 20 }}>
4054
<DefaultButton onClick={goBack} text={t('common.cancel')} />
41-
<PrimaryButton disabled={invalidParams || notModified} onClick={handleSubmit} text={t('common.save')} />
55+
<PrimaryButton disabled={errors.includes(true) || notModified} onClick={handleSubmit} text={t('common.save')} />
4256
</Stack>
4357
</Stack>
4458
)

packages/neuron-ui/src/locales/en.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@
239239
"addr-copied": "Address has been copied to the clipboard",
240240
"qrcode-copied": "QR Code has been copied to the clipboard",
241241
"lock-arg-copied": "Lock Arg has been copied to the clipboard",
242-
"transaction-not-found": "The transaction is not found"
242+
"transaction-not-found": "The transaction is not found",
243+
"rpc-url-should-have-protocol": "The RPC URL should start with http(s)://",
244+
"rpc-url-should-have-no-whitespaces": "The RPC URL should have no whitespaces"
243245
},
244246
"sync": {
245247
"syncing": "Syncing",

packages/neuron-ui/src/locales/zh.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,9 @@
239239
"addr-copied": "地址已复制到剪贴板",
240240
"qrcode-copied": "二维码已复制到剪贴板",
241241
"lock-arg-copied": "Lock Arg 已复制到剪贴板",
242-
"transaction-not-found": "未找到交易"
242+
"transaction-not-found": "未找到交易",
243+
"network-address-should-have-protocol": "RPC 地址应以 http(s)//: 开始",
244+
"network-address-should-have-no-whitespaces": "RPC 地址不能包含空格"
243245
},
244246
"sync": {
245247
"syncing": "同步中",

0 commit comments

Comments
 (0)