Update instance-create to handle both v4 and v6 ephemeral IP options#3057
Update instance-create to handle both v4 and v6 ephemeral IP options#3057charliepark wants to merge 15 commits intomainfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
c1fc16d to
fc14295
Compare
app/forms/instance-create.tsx
Outdated
| type: 'ephemeral' as const, | ||
| poolSelector: values.ephemeralIpv4Pool | ||
| ? { type: 'explicit' as const, pool: values.ephemeralIpv4Pool } | ||
| : { type: 'auto' as const, ipVersion: 'v4' as const }, |
There was a problem hiding this comment.
I don't think we need the auto case in these because we always have a pool — see the comment in the deleted code
app/forms/instance-create.tsx
Outdated
| () => unicastPools.filter(poolHasIpVersion(compatibleVersions)), | ||
| [unicastPools, compatibleVersions] | ||
| ) | ||
| .filter((ip): ip is FloatingIp => !!ip) |
There was a problem hiding this comment.
Type guard shouldn't be necessary as far as I know — is it?
There was a problem hiding this comment.
The flow to end up in a state where it's actually useful is pretty rare …
- User selects "ip-1" from modal → added to attachedFloatingIps (form state)
- React Query refetches floatingIpList (on window focus, reconnect, or stale time expiry)
- "ip-1" is now attached to another instance or deleted (via some other user on the system)
- "ip-1" filtered out of attachableFloatingIps
- Form state still has "ip-1", but .find() can't find it
But TS complains* unless it has either a filter (.filter((ip) => ip !== undefined) or .filter((ip) => !!ip)), or an ! assertion (floatingIp) => attachableFloatingIps.find((fip) => fip.name === floatingIp)!
- The complaint is in the MiniTable, where an
itemmight be undefined.
I'm moving to an assertion as that should throw an error if the user ends up in that state, versus having the Floating IP silently disappear, but I'm open to filtering if that feels like a better situation.
app/forms/instance-create.tsx
Outdated
| </div> | ||
| ) | ||
| } | ||
|
|
There was a problem hiding this comment.
Don't define components in render. Probably worth putting in the CLAUDE.md. There's an eslint rule for this, react/no-unstable-nested-components, but oxlint doesn't have it yet.
app/forms/instance-create.tsx
Outdated
| <br /> | ||
| for this instance’s network interfaces | ||
| </> | ||
| ) |
There was a problem hiding this comment.
These and getDisabledReason should be defined at top level probably. They're pure functions.
app/forms/instance-create.tsx
Outdated
| poolFieldName={poolFieldName} | ||
| pools={pools} | ||
| disabled={isSubmitting} | ||
| required={false} |
There was a problem hiding this comment.
In the previous version this wasn't conditionally rendered — I used a class to hide it while keeping it mounted so that I could have the required prop change its value on the form, enforcing required when the box was checked but not when it was unchecked. Hard coding required: false avoids that problem because the requirement never changes, but it only works if we can guarantee that there is always a pool selected when we expect there to be.
const defaultV4Pool = compatibleDefaultPools.find((p) => p.ipVersion === 'v4')
const defaultV6Pool = compatibleDefaultPools.find((p) => p.ipVersion === 'v6')
...
ephemeralIpv4: !!defaultV4Pool && defaultCompatibleVersions.includes('v4'),
ephemeralIpv4Pool: defaultV4Pool?.name || '',
ephemeralIpv6: !!defaultV6Pool && defaultCompatibleVersions.includes('v6'),
ephemeralIpv6Pool: defaultV6Pool?.name || '',This logic means that if there is a v6 pool but there is no default v6 pool, then it's possible to check the IPv6 ephemeral IP box but not select a pool. I was able to confirm this by hand with the pelerines silo, which has a v6 pool but no default. It lets me check the box and not pick a pool, and then I get an error from the API.
But if instead you always render IpPoolSelector, hide it when the checkbox is unchecked, and have required={checked}, you solve this problem with form validation — it's a form error to not have a pool picked. In hindsight I should have left a comment on required={assignEphemeralIp} and the hidden class thing explaining what it was for.



Instances can now have both IPv4- and IPv6-backed ephemeral IPs. This updates the instance create flow to account for that.
It checks / unchecks the ephemeral IP box for the IP version(s) specified in the Network Interfaces section of the form.
Default NICs



Custom NICs



No NIC

Closes #3041