more validation work
This commit is contained in:
@@ -41,7 +41,7 @@ export const BalanceCard = () => {
|
|||||||
{balanceError}
|
{balanceError}
|
||||||
</Alert>
|
</Alert>
|
||||||
) : (
|
) : (
|
||||||
<Typography>{balance?.printableBalance}</Typography>
|
<Typography>{balance?.printable_balance}</Typography>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -11,15 +11,9 @@ import {
|
|||||||
import { useTheme } from '@material-ui/styles'
|
import { useTheme } from '@material-ui/styles'
|
||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { yupResolver } from '@hookform/resolvers/yup'
|
import { yupResolver } from '@hookform/resolvers/yup'
|
||||||
import * as Yup from 'yup'
|
|
||||||
import { EnumNodeType } from '../../types/global'
|
import { EnumNodeType } from '../../types/global'
|
||||||
import { NodeTypeSelector } from '../../components/NodeTypeSelector'
|
import { NodeTypeSelector } from '../../components/NodeTypeSelector'
|
||||||
import {
|
import { validationSchema } from './validationSchema'
|
||||||
isValidHostname,
|
|
||||||
validateAmount,
|
|
||||||
validateKey,
|
|
||||||
validateVersion,
|
|
||||||
} from '../../utils'
|
|
||||||
|
|
||||||
type TBondNodeFormProps = {
|
type TBondNodeFormProps = {
|
||||||
// minimumBond: Coin
|
// minimumBond: Coin
|
||||||
@@ -27,74 +21,80 @@ type TBondNodeFormProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TBondFormFields = {
|
type TBondFormFields = {
|
||||||
|
nodeType: EnumNodeType
|
||||||
identityKey: string
|
identityKey: string
|
||||||
sphinxKey: string
|
sphinxKey: string
|
||||||
amount: string
|
amount: string
|
||||||
host: string
|
host: string
|
||||||
version: string
|
version: string
|
||||||
|
location?: string
|
||||||
|
mixPort: number
|
||||||
|
verlocPort: number
|
||||||
|
clientsPort: number
|
||||||
|
httpApiPort: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const defaultPorts = {
|
||||||
identityKey: Yup.string()
|
mixPort: 1789,
|
||||||
.required('An indentity key is required')
|
verlocPort: 1790,
|
||||||
.test('valid-id-key', 'A valid identity key is required', function (value) {
|
httpApiPort: 8000,
|
||||||
return validateKey(value || '')
|
clientsPort: 9000,
|
||||||
}),
|
}
|
||||||
sphinxKey: Yup.string()
|
|
||||||
.required('A sphinx key is required')
|
|
||||||
.test(
|
|
||||||
'valid-sphinx-key',
|
|
||||||
'A valid sphinx key is required',
|
|
||||||
function (value) {
|
|
||||||
return validateKey(value || '')
|
|
||||||
}
|
|
||||||
),
|
|
||||||
amount: Yup.string()
|
|
||||||
.required('An amount is required')
|
|
||||||
.test(
|
|
||||||
'valid-amount',
|
|
||||||
'A valid amount is required (min 100 punks)',
|
|
||||||
function (value) {
|
|
||||||
return validateAmount(value || '', '100000000')
|
|
||||||
// minimum amount needs to come from the backend - replace when available
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
host: Yup.string()
|
const defaultValues = {
|
||||||
.required('A host is required')
|
nodeType: EnumNodeType.Mixnode,
|
||||||
.test('valid-amount', 'A valid host is required', function (value) {
|
identityKey: '',
|
||||||
return !!value ? isValidHostname(value) : false
|
sphinxKey: '',
|
||||||
}),
|
amount: '',
|
||||||
version: Yup.string()
|
host: '',
|
||||||
.required('A version is required')
|
version: '',
|
||||||
.test('valid-version', 'A valid version is required', function (value) {
|
location: undefined,
|
||||||
return !!value ? validateVersion(value) : false
|
...defaultPorts,
|
||||||
}),
|
}
|
||||||
})
|
|
||||||
|
|
||||||
export const BondNodeForm = () => {
|
export const BondNodeForm = () => {
|
||||||
const [advancedShown, setAdvancedShown] = React.useState(false)
|
const [advancedShown, setAdvancedShown] = React.useState(false)
|
||||||
const [nodeType, setNodeType] = useState(EnumNodeType.Mixnode)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
reset,
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
setValue,
|
||||||
|
watch,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm<TBondFormFields>({ resolver: yupResolver(validationSchema) })
|
} = useForm<TBondFormFields>({
|
||||||
|
resolver: yupResolver(validationSchema),
|
||||||
|
defaultValues,
|
||||||
|
})
|
||||||
|
|
||||||
const theme: Theme = useTheme()
|
const watchNodeType = watch('nodeType', EnumNodeType.Mixnode)
|
||||||
console.log(errors)
|
|
||||||
|
|
||||||
const onSubmit = (data: TBondFormFields) => console.log(data)
|
const onSubmit = (data: TBondFormFields) => console.log(data)
|
||||||
|
|
||||||
|
const theme: Theme = useTheme()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form>
|
<form>
|
||||||
<div style={{ padding: theme.spacing(3, 5) }}>
|
<div style={{ padding: theme.spacing(3, 5) }}>
|
||||||
<Grid container spacing={3}>
|
<Grid container spacing={3}>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<NodeTypeSelector
|
<NodeTypeSelector
|
||||||
nodeType={nodeType}
|
nodeType={watchNodeType}
|
||||||
setNodeType={(nodeType) => setNodeType(nodeType)}
|
setNodeType={(nodeType) => {
|
||||||
|
setValue('nodeType', nodeType)
|
||||||
|
// reset(
|
||||||
|
// {
|
||||||
|
// // location:
|
||||||
|
// // nodeType === EnumNodeType.Mixnode ? undefined : '',
|
||||||
|
// ...defaultPorts,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// keepErrors: true,
|
||||||
|
// keepDirty: true,
|
||||||
|
// keepValues: true,
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
@@ -158,14 +158,17 @@ export const BondNodeForm = () => {
|
|||||||
|
|
||||||
{/* if it's a gateway - get location */}
|
{/* if it's a gateway - get location */}
|
||||||
<Grid item xs={6}>
|
<Grid item xs={6}>
|
||||||
{nodeType === EnumNodeType.Gateway && (
|
{watchNodeType === EnumNodeType.Gateway && (
|
||||||
<TextField
|
<TextField
|
||||||
|
{...register('location')}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
required
|
required
|
||||||
id="location"
|
id="location"
|
||||||
name="location"
|
name="location"
|
||||||
label="Location"
|
label="Location"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
error={!!errors.location}
|
||||||
|
helperText={errors.location?.message}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -191,6 +194,13 @@ export const BondNodeForm = () => {
|
|||||||
checked={advancedShown}
|
checked={advancedShown}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setAdvancedShown((shown) => {
|
setAdvancedShown((shown) => {
|
||||||
|
if (shown) {
|
||||||
|
reset(defaultPorts, {
|
||||||
|
keepErrors: true,
|
||||||
|
keepDirty: true,
|
||||||
|
keepValues: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
return !shown
|
return !shown
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
@@ -204,43 +214,66 @@ export const BondNodeForm = () => {
|
|||||||
<>
|
<>
|
||||||
<Grid item xs={12} sm={4}>
|
<Grid item xs={12} sm={4}>
|
||||||
<TextField
|
<TextField
|
||||||
|
{...register('mixPort', { valueAsNumber: true })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
id="mixPort"
|
id="mixPort"
|
||||||
name="mixPort"
|
name="mixPort"
|
||||||
label="Mix Port"
|
label="Mix Port"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
error={!!errors.mixPort}
|
||||||
|
helperText={
|
||||||
|
errors.mixPort?.message && 'A valid port value is required'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
{nodeType === EnumNodeType.Mixnode ? (
|
{watchNodeType === EnumNodeType.Mixnode ? (
|
||||||
<>
|
<>
|
||||||
<Grid item xs={12} sm={4}>
|
<Grid item xs={12} sm={4}>
|
||||||
<TextField
|
<TextField
|
||||||
|
{...register('verlocPort', { valueAsNumber: true })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
id="verlocPort"
|
id="verlocPort"
|
||||||
name="verlocPort"
|
name="verlocPort"
|
||||||
label="Verloc Port"
|
label="Verloc Port"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
error={!!errors.verlocPort}
|
||||||
|
helperText={
|
||||||
|
errors.verlocPort?.message &&
|
||||||
|
'A valid port value is required'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} sm={4}>
|
<Grid item xs={12} sm={4}>
|
||||||
<TextField
|
<TextField
|
||||||
|
{...register('httpApiPort', { valueAsNumber: true })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
id="httpApiPort"
|
id="httpApiPort"
|
||||||
name="httpApiPort"
|
name="httpApiPort"
|
||||||
label="HTTP API Port"
|
label="HTTP API Port"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
error={!!errors.httpApiPort}
|
||||||
|
helperText={
|
||||||
|
errors.httpApiPort?.message &&
|
||||||
|
'A valid port value is required'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Grid item xs={12} sm={4}>
|
<Grid item xs={12} sm={4}>
|
||||||
<TextField
|
<TextField
|
||||||
|
{...register('clientsPort', { valueAsNumber: true })}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
id="clientsPort"
|
id="clientsPort"
|
||||||
name="clientsPort"
|
name="clientsPort"
|
||||||
label="client WS API Port"
|
label="client WS API Port"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
error={!!errors.clientsPort}
|
||||||
|
helperText={
|
||||||
|
errors.clientsPort?.message &&
|
||||||
|
'A valid port value is required'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
@@ -259,6 +292,7 @@ export const BondNodeForm = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={Object.keys(errors).length > 0}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import * as Yup from 'yup'
|
||||||
|
import {
|
||||||
|
isValidHostname,
|
||||||
|
validateAmount,
|
||||||
|
validateKey,
|
||||||
|
validateLocation,
|
||||||
|
validateRawPort,
|
||||||
|
validateVersion,
|
||||||
|
} from '../../utils'
|
||||||
|
|
||||||
|
export const validationSchema = Yup.object().shape({
|
||||||
|
identityKey: Yup.string()
|
||||||
|
.required('An indentity key is required')
|
||||||
|
.test('valid-id-key', 'A valid identity key is required', function (value) {
|
||||||
|
return validateKey(value || '')
|
||||||
|
}),
|
||||||
|
sphinxKey: Yup.string()
|
||||||
|
.required('A sphinx key is required')
|
||||||
|
.test(
|
||||||
|
'valid-sphinx-key',
|
||||||
|
'A valid sphinx key is required',
|
||||||
|
function (value) {
|
||||||
|
return validateKey(value || '')
|
||||||
|
}
|
||||||
|
),
|
||||||
|
amount: Yup.string()
|
||||||
|
.required('An amount is required')
|
||||||
|
.test(
|
||||||
|
'valid-amount',
|
||||||
|
'A valid amount is required (min 100 punks)',
|
||||||
|
function (value) {
|
||||||
|
return validateAmount(value || '', '100000000')
|
||||||
|
// minimum amount needs to come from the backend - replace when available
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
host: Yup.string()
|
||||||
|
.required('A host is required')
|
||||||
|
.test('valid-host', 'A valid host is required', function (value) {
|
||||||
|
return !!value ? isValidHostname(value) : false
|
||||||
|
}),
|
||||||
|
version: Yup.string()
|
||||||
|
.required('A version is required')
|
||||||
|
.test('valid-version', 'A valid version is required', function (value) {
|
||||||
|
return !!value ? validateVersion(value) : false
|
||||||
|
}),
|
||||||
|
location: Yup.lazy((value) => {
|
||||||
|
console.log('LOCATION = ' + value)
|
||||||
|
if (!!value) {
|
||||||
|
return Yup.string()
|
||||||
|
.required('A location is required')
|
||||||
|
.test(
|
||||||
|
'valid-location',
|
||||||
|
'A valid version is required',
|
||||||
|
function (value) {
|
||||||
|
return !!value ? validateLocation(value) : false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return Yup.mixed().notRequired()
|
||||||
|
}),
|
||||||
|
mixPort: Yup.number()
|
||||||
|
.required('A mixport is required')
|
||||||
|
.test('valid-mixport', 'A valid mixport is required', function (value) {
|
||||||
|
return !!value ? validateRawPort(value) : false
|
||||||
|
}),
|
||||||
|
verlocPort: Yup.number()
|
||||||
|
.required('A verloc port is required')
|
||||||
|
.test('valid-verloc', 'A valid verloc port is required', function (value) {
|
||||||
|
return !!value ? validateRawPort(value) : false
|
||||||
|
}),
|
||||||
|
httpApiPort: Yup.number()
|
||||||
|
.required('A http-api port is required')
|
||||||
|
.test('valid-http', 'A valid http-api port is required', function (value) {
|
||||||
|
return !!value ? validateRawPort(value) : false
|
||||||
|
}),
|
||||||
|
clientsPort: Yup.number()
|
||||||
|
.required('A clients port is required')
|
||||||
|
.test(
|
||||||
|
'valid-clients',
|
||||||
|
'A valid clients port is required',
|
||||||
|
function (value) {
|
||||||
|
return !!value ? validateRawPort(value) : false
|
||||||
|
}
|
||||||
|
),
|
||||||
|
})
|
||||||
@@ -16,7 +16,7 @@ export type TNodeOwnership = {
|
|||||||
export type TBalance = {
|
export type TBalance = {
|
||||||
amount: string
|
amount: string
|
||||||
demon: EnumDemon
|
demon: EnumDemon
|
||||||
printableBalance: string
|
printable_balance: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TClientDetails = {
|
export type TClientDetails = {
|
||||||
|
|||||||
@@ -78,3 +78,11 @@ export const validateVersion = (version: string): boolean => {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const validateLocation = (location: string): boolean => {
|
||||||
|
// right now only perform the stupid check of whether the user copy-pasted the tooltip... (with or without brackets)
|
||||||
|
return !location.trim().includes('physical location of your node')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateRawPort = (rawPort: number): boolean =>
|
||||||
|
!isNaN(rawPort) && rawPort >= 1 && rawPort <= 65535
|
||||||
|
|||||||
Reference in New Issue
Block a user