@@ -41,62 +41,43 @@ const defaultValues: MemberAddForm = {
4141 maxPrefixLength : NaN ,
4242}
4343
44- // Uses form-level validate (RHF ≥7.72.0) so we can look at all three fields
45- // together. Unlike `resolver`, this runs alongside field-level validation, so
46- // `required` / `min` / `max` on the fields still apply.
47- export function validateForm ( poolVersion : IpVersion , values : MemberAddForm ) {
44+ type ValidationErrors = Partial < Record < keyof MemberAddForm , string > >
45+
46+ export function validateMember ( poolVersion : IpVersion , values : MemberAddForm ) {
4847 const maxBound = poolVersion === 'v4' ? 32 : 128
4948 const parsed = parseIpNet ( values . subnet )
5049 const { minPrefixLength : minPL , maxPrefixLength : maxPL } = values
5150 const subnetWidth = parsed . type !== 'error' ? parsed . width : undefined
5251 const inRange = ( v : number ) => ! Number . isNaN ( v ) && v >= 0 && v <= maxBound
5352
54- const errors : Partial < Record < keyof MemberAddForm , { type : string ; message : string } > > = { }
53+ const errors : ValidationErrors = { }
5554
5655 if ( parsed . type === 'error' ) {
57- errors . subnet = { type : 'pattern' , message : parsed . message }
56+ errors . subnet = parsed . message
5857 } else if ( parsed . type !== poolVersion ) {
59- errors . subnet = {
60- type : 'pattern' ,
61- message : `IP${ parsed . type } subnet not allowed in IP${ poolVersion } pool` ,
62- }
58+ errors . subnet = `IP${ parsed . type } subnet not allowed in IP${ poolVersion } pool`
6359 }
6460
6561 // min and max prefix length are optional, and NaN is the value they have
6662 // when they're unset (matching NumberField)
6763
6864 // min prefix: bounds → ordering → subnet width
6965 if ( ! Number . isNaN ( minPL ) && ! inRange ( minPL ) ) {
70- errors . minPrefixLength = {
71- type : 'validate' ,
72- message : `Must be between 0 and ${ maxBound } ` ,
73- }
66+ errors . minPrefixLength = `Must be between 0 and ${ maxBound } `
7467 } else if ( inRange ( minPL ) && inRange ( maxPL ) && minPL > maxPL ) {
75- errors . minPrefixLength = {
76- type : 'validate' ,
77- message : 'Min prefix length must be ≤ max prefix length' ,
78- }
68+ errors . minPrefixLength = 'Min prefix length must be ≤ max prefix length'
7969 } else if ( inRange ( minPL ) && subnetWidth !== undefined && minPL < subnetWidth ) {
80- errors . minPrefixLength = {
81- type : 'validate' ,
82- message : `Must be ≥ subnet prefix length (${ subnetWidth } )` ,
83- }
70+ errors . minPrefixLength = `Must be ≥ subnet prefix length (${ subnetWidth } )`
8471 }
8572
8673 // max prefix: bounds → subnet width
8774 if ( ! Number . isNaN ( maxPL ) && ! inRange ( maxPL ) ) {
88- errors . maxPrefixLength = {
89- type : 'validate' ,
90- message : `Must be between 0 and ${ maxBound } ` ,
91- }
75+ errors . maxPrefixLength = `Must be between 0 and ${ maxBound } `
9276 } else if ( inRange ( maxPL ) && subnetWidth !== undefined && maxPL < subnetWidth ) {
93- errors . maxPrefixLength = {
94- type : 'validate' ,
95- message : `Must be ≥ subnet prefix length (${ subnetWidth } )` ,
96- }
77+ errors . maxPrefixLength = `Must be ≥ subnet prefix length (${ subnetWidth } )`
9778 }
9879
99- return Object . keys ( errors ) . length > 0 ? errors : true
80+ return errors
10081}
10182
10283export const handle = titleCrumb ( 'Add Member' )
@@ -120,10 +101,7 @@ export default function SubnetPoolMemberAdd() {
120101 } ,
121102 } )
122103
123- const form = useForm < MemberAddForm > ( {
124- defaultValues,
125- validate : ( { formValues } ) => validateForm ( poolData . ipVersion , formValues ) ,
126- } )
104+ const form = useForm < MemberAddForm > ( { defaultValues } )
127105
128106 const maxBound = poolData . ipVersion === 'v4' ? 32 : 128
129107
@@ -157,6 +135,8 @@ export default function SubnetPoolMemberAdd() {
157135 description = "CIDR notation (e.g., 10.0.0.0/16)"
158136 control = { form . control }
159137 required
138+ validate = { ( _subnet , values ) => validateMember ( poolData . ipVersion , values ) . subnet }
139+ deps = { [ 'minPrefixLength' , 'maxPrefixLength' ] }
160140 />
161141 < NumberField
162142 name = "minPrefixLength"
@@ -165,6 +145,9 @@ export default function SubnetPoolMemberAdd() {
165145 control = { form . control }
166146 min = { 0 }
167147 max = { maxBound }
148+ validate = { ( _minPrefixLength , values ) =>
149+ validateMember ( poolData . ipVersion , values ) . minPrefixLength
150+ }
168151 />
169152 < NumberField
170153 name = "maxPrefixLength"
@@ -173,6 +156,10 @@ export default function SubnetPoolMemberAdd() {
173156 control = { form . control }
174157 min = { 0 }
175158 max = { maxBound }
159+ validate = { ( _maxPrefixLength , values ) =>
160+ validateMember ( poolData . ipVersion , values ) . maxPrefixLength
161+ }
162+ deps = "minPrefixLength"
176163 />
177164 < SideModalFormDocs docs = { [ docLinks . subnetPools ] } />
178165 </ SideModalForm >
0 commit comments