Skip to content

refactor(web): network connection form UX (part 6)#3353

Merged
dgdavid merged 2 commits intoenhance-network-connection-formfrom
network-tanstack-form-part6
Apr 7, 2026
Merged

refactor(web): network connection form UX (part 6)#3353
dgdavid merged 2 commits intoenhance-network-connection-formfrom
network-tanstack-form-part6

Conversation

@dgdavid
Copy link
Copy Markdown
Contributor

@dgdavid dgdavid commented Apr 1, 2026

Built on top of #3352, this PR fixes a small but noticeable UX gap found while recording the screencast for the referenced PR: when switching between "Chosen by name" and "Chosen by MAC" binding modes, the device selection was lost and the user had to re-pick it.

To fix it, one of the components has gained the ability to trigger listeners on demand, making it possible to wire the two different selectors instantiated under the hood and keep them in sync. Note that although only one instance is mounted at a time and there is no real risk of listener loops, dontRunListeners: true is still passed to the setFieldValue call inside the listener as a safety net.

network-device-selectors-in-sync.mp4

For more details, check the changes.

Related to:


Notes for reviewers

By adding a `sync` prop to `DeviceSelector` that registers a TanStack Form
listener to write a derived value into a second field whenever a device
is selected.
@dgdavid dgdavid force-pushed the network-tanstack-form-part6 branch from 34217e7 to d7801c4 Compare April 1, 2026 15:29
@dgdavid

This comment was marked as resolved.

@imobachgs imobachgs marked this pull request as draft April 7, 2026 11:13
@dgdavid dgdavid force-pushed the network-tanstack-form-part6 branch from e70dc8e to 21448ad Compare April 7, 2026 13:27
@dgdavid dgdavid changed the base branch from master to enhance-network-connection-form April 7, 2026 13:27
@dgdavid dgdavid marked this pull request as ready for review April 7, 2026 13:28
@dgdavid dgdavid merged commit 22a43d3 into enhance-network-connection-form Apr 7, 2026
15 checks passed
@dgdavid dgdavid deleted the network-tanstack-form-part6 branch April 7, 2026 14:33
dgdavid added a commit that referenced this pull request Apr 8, 2026
This is the final PR of series of changes for reimplementing the network
connection form using [TanStack Form](https://tanstack.com/form/). Built
on top of #3353, it removes the old IP settings form and its
dependencies, completes the field component set, improves the name
auto-sync approach, and fixes a validation gap in advanced mode.

### Removal of IpSettingsForm

`IpSettingsForm` and its supporting components (`AddressesDataList`,
`DnsDataList`, `DnsSearchDataList`, `IpAddressInput`, `IpPrefixInput`,
and their tests) are deleted. The new `ConnectionForm` based on TanStack
Form fully replaces them.

### Bug fix: address validation in advanced mode

Addresses are optional in advanced mode, but if entered they must still
be valid. Previously only manual mode validated them, so invalid entries
could silently reach the server. The fix ensures to also validate
entries when they are present in advanced mode, even though none are
required.

### `generateConnectionName` as a pure function

`useConnectionName` was a React hook that had no real React dependency:
it computed a name from its arguments and returned a string. It has been
replaced by `generateConnectionName`, a plain function in
`src/utils/network.ts` that is easier to test and works anywhere without
a component context.

### Name auto-sync via form-level listeners

The previous approach used `useStore` to watch binding fields and a
`useEffect` to write the derived name back. Both are replaced by
TanStack Form's own [`listeners`
API](https://tanstack.com/form/latest/docs/framework/react/guides/listeners)),
which is the idiomatic way to handle field side effects in this library.

The listener fires on mount and on every change and, as in previous
approach, it skips the update when the name field is already dirty,
[using `isDirty` rather than
`isTouched`](https://tanstack.com/form/latest/docs/framework/react/guides/basic-concepts#field-state)
so that focusing and blurring the field without typing does not stop
auto-generation. [`dontRunListeners:
true`](https://github.com/TanStack/form/blob/42761767cf0662559d4f2c1a51b45b3720dbd451/packages/form-core/src/FieldApi.ts#L1446-L1449)
prevents the name write from re-triggering the listener.

### DropdownField rename

`ChoiceField` was renamed to `DropdownField` since the old name gave no
hint about what kind of input it renders. The TSDoc now explains that
the component uses a PatternFly menu-based combobox rather than a native
`<select>`, why the keyboard interaction differs from what users may
expect, and includes a TODO for implementing the W3C-recommended
arrow-key compromise.

### TextField and CheckboxField

Two new field components following the same `useFieldContext` pattern as
`DropdownField` and `ArrayField`:

- `TextField`: a text input that shows validation errors inline below
the input.
- `CheckboxField`: a checkbox with an optional description.

Both are registered in `useAppForm` and wired into `ConnectionForm`
(name field, DNS toggles) and `IpSettings` (gateway field), replacing
the inline markup that was previously scattered across those components.

A `## Field component conventions` section was added to
`form-contexts.ts` to document the shared contract: `onChange` is wired
internally, `onBlur` is intentionally not wired (submit-only validation,
revisit when a use case arises), and lifecycle events belong on
`form.AppField` via `listeners`, not on the component itself.

### Action button form components

Two action button components are registered under `formComponents` so
they are available on any typed form instance without form-specific
wiring:

- `form.SubmitButton`: reads `isSubmitting` via `useFormContext` and
renders a submit button that shows a loading indicator and disables
itself while the form is submitting.
- `form.CancelButton`: encapsulates `navigate(-1)` via `useNavigate`,
rendering a link button that returns to the previous page.

`ConnectionForm`'s action group reduces to:

```tsx
<ActionGroup>
  <form.SubmitButton />
  <form.CancelButton />
</ActionGroup>
```
### Form conventions update

`src/components/form/conventions.md` has been updated to reflect the
implemented state of `ConnectionForm`. Stale notes are replaced with
accurate descriptions, conditional rendering is consistently described
as "not rendered" rather than "hidden" throughout, and a new Validation
section explains the submit-only approach, the cross-field
`onSubmitAsync` pattern, and the `setErrorMap` workaround needed to
re-enable submission after a failed attempt.
@imobachgs imobachgs mentioned this pull request Apr 14, 2026
imobachgs added a commit that referenced this pull request Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants