more validation work

This commit is contained in:
fmtabbara
2021-09-02 10:10:18 +01:00
parent f043639ad2
commit bd7d788741
5 changed files with 181 additions and 53 deletions
@@ -41,7 +41,7 @@ export const BalanceCard = () => {
{balanceError} {balanceError}
</Alert> </Alert>
) : ( ) : (
<Typography>{balance?.printableBalance}</Typography> <Typography>{balance?.printable_balance}</Typography>
)} )}
</div> </div>
</CardContent> </CardContent>
+85 -51
View File
@@ -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
}
),
})
+1 -1
View File
@@ -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 = {
+8
View File
@@ -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