From 864501456dd3b8627a7ac68d45435c89f5a4e545 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Thu, 22 Oct 2026 14:47:58 -0500 Subject: [PATCH 1/3] Fix Enter on floating IP picker creating instance The attach floating IP modal wrapped its Listbox in a bare
. Headless UI ListboxButton requests submit on the nearest form when Enter is pressed, and React bubbles the submit event through the modal portal to the instance create form, so pressing Enter on the closed picker created the instance. The modal has no form logic of its own, so drop the wrapper. --- app/forms/instance-create.tsx | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/app/forms/instance-create.tsx b/app/forms/instance-create.tsx index 937a717a8..193a4f571 100644 --- a/app/forms/instance-create.tsx +++ b/app/forms/instance-create.tsx @@ -1053,23 +1053,24 @@ const NetworkingSection = ({ - - ({ - value: i.name, - label: , - selectedLabel: `${i.name} (${i.ip})`, - }))} - label="Floating IP" - onChange={(name) => { - setSelectedFloatingIp(availableFloatingIps.find((i) => i.name === name)) - }} - required - placeholder="Select a floating IP" - selected={selectedFloatingIp?.name || ''} - /> - + {/* No
here: this modal is inside the instance create form in + the React tree, so a submit event would bubble through the portal + and submit the whole instance create form */} + ({ + value: i.name, + label: , + selectedLabel: `${i.name} (${i.ip})`, + }))} + label="Floating IP" + onChange={(name) => { + setSelectedFloatingIp(availableFloatingIps.find((i) => i.name === name)) + }} + required + placeholder="Select a floating IP" + selected={selectedFloatingIp?.name || ''} + /> Date: Thu, 22 Oct 2026 14:47:58 -0500 Subject: [PATCH 2/3] Hook up Link silo and Link pool modal submit buttons --- app/pages/system/networking/IpPoolPage.tsx | 6 ++++-- app/pages/system/silos/SiloIpPoolsTab.tsx | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/pages/system/networking/IpPoolPage.tsx b/app/pages/system/networking/IpPoolPage.tsx index 5ed9352ed..d6a27b0db 100644 --- a/app/pages/system/networking/IpPoolPage.tsx +++ b/app/pages/system/networking/IpPoolPage.tsx @@ -8,7 +8,7 @@ import { useQuery } from '@tanstack/react-query' import { createColumnHelper } from '@tanstack/react-table' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useId, useMemo, useState } from 'react' import { useForm, useWatch } from 'react-hook-form' import { Outlet, useNavigate } from 'react-router' @@ -484,6 +484,7 @@ const toSiloComboboxItem = ({ name, description }: Silo): ComboboxItem => ({ }) function LinkSiloModal({ onDismiss }: { onDismiss: () => void }) { + const formId = useId() const { pool } = useIpPoolSelector() const { data: poolData } = usePrefetchedQuery(ipPoolView({ pool })) const { control, handleSubmit } = useForm({ defaultValues }) @@ -545,6 +546,7 @@ function LinkSiloModal({ onDismiss }: { onDismiss: () => void }) { { e.stopPropagation() @@ -580,7 +582,7 @@ function LinkSiloModal({ onDismiss }: { onDismiss: () => void }) { diff --git a/app/pages/system/silos/SiloIpPoolsTab.tsx b/app/pages/system/silos/SiloIpPoolsTab.tsx index 6c6f14048..5560dd131 100644 --- a/app/pages/system/silos/SiloIpPoolsTab.tsx +++ b/app/pages/system/silos/SiloIpPoolsTab.tsx @@ -8,7 +8,7 @@ import { useQuery } from '@tanstack/react-query' import { createColumnHelper } from '@tanstack/react-table' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useId, useMemo, useState } from 'react' import { useForm, useWatch } from 'react-hook-form' import { @@ -284,6 +284,7 @@ type LinkPoolFormValues = { const defaultValues: LinkPoolFormValues = { pool: undefined, isDefault: false } function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) { + const formId = useId() const { silo } = useSiloSelector() const { control, handleSubmit } = useForm({ defaultValues }) @@ -338,6 +339,7 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) { { e.stopPropagation() @@ -375,7 +377,7 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) { From 8e3a5e8cef92c0657e16a322c23c126a32288a05 Mon Sep 17 00:00:00 2001 From: David Crespo Date: Thu, 22 Oct 2026 16:11:28 -0500 Subject: [PATCH 3/3] Hook up subnet pool link modal submit buttons --- app/pages/system/networking/SubnetPoolPage.tsx | 6 ++++-- app/pages/system/silos/SiloSubnetPoolsTab.tsx | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/pages/system/networking/SubnetPoolPage.tsx b/app/pages/system/networking/SubnetPoolPage.tsx index 27ed903b3..ae9507d0b 100644 --- a/app/pages/system/networking/SubnetPoolPage.tsx +++ b/app/pages/system/networking/SubnetPoolPage.tsx @@ -8,7 +8,7 @@ import { useQuery } from '@tanstack/react-query' import { createColumnHelper } from '@tanstack/react-table' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useId, useMemo, useState } from 'react' import { useForm, useWatch } from 'react-hook-form' import { Outlet, useNavigate } from 'react-router' @@ -469,6 +469,7 @@ const toSiloComboboxItem = ({ name, description }: Silo): ComboboxItem => ({ }) function LinkSiloModal({ onDismiss }: { onDismiss: () => void }) { + const formId = useId() const poolSelector = useSubnetPoolSelector() const { subnetPool } = poolSelector const { data: poolData } = usePrefetchedQuery(subnetPoolView(poolSelector)) @@ -530,6 +531,7 @@ function LinkSiloModal({ onDismiss }: { onDismiss: () => void }) { { e.stopPropagation() @@ -565,7 +567,7 @@ function LinkSiloModal({ onDismiss }: { onDismiss: () => void }) { diff --git a/app/pages/system/silos/SiloSubnetPoolsTab.tsx b/app/pages/system/silos/SiloSubnetPoolsTab.tsx index 5ce938dbd..557bebd6f 100644 --- a/app/pages/system/silos/SiloSubnetPoolsTab.tsx +++ b/app/pages/system/silos/SiloSubnetPoolsTab.tsx @@ -8,7 +8,7 @@ import { useQuery } from '@tanstack/react-query' import { createColumnHelper } from '@tanstack/react-table' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useId, useMemo, useState } from 'react' import { useForm, useWatch } from 'react-hook-form' import { @@ -271,6 +271,7 @@ type LinkPoolFormValues = { const defaultValues: LinkPoolFormValues = { pool: undefined, isDefault: false } function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) { + const formId = useId() const { silo } = useSiloSelector() const { control, handleSubmit } = useForm({ defaultValues }) @@ -319,6 +320,7 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) { { e.stopPropagation() @@ -356,7 +358,7 @@ function LinkPoolModal({ onDismiss }: { onDismiss: () => void }) {