feature(web): redesign network connection form with improved UX#3386
Merged
feature(web): redesign network connection form with improved UX#3386
Conversation
Adds @tanstack/react-form as a project dependency. TanStack Form will be used to replace the current ad-hoc form state management, starting with the network connection form. Check https://tanstack.com/form/latest
This commit starts the reimplementation of the network connection form
using TanStack Form, replacing the previous ad-hoc form state management
with a structured, library-backed approach.
The form is intentionally minimal in this first iteration, name and
interface fields only, to establish the pattern cleanly before adding
complexity. The full form (IP settings, bond/bridge/VLAN config, etc)
will be built incrementally in subsequent commits.
TanStack Form was chosen for:
- Declarative field registration with built-in state (dirty, touched,
errors) per field, without manual useState plumbing
- Type-safe form values inferred from defaultValues
- A clean model for handling server errors via onSubmitAsync: the error
is surfaced in the UI without throwing, keeping the form interactive
so the user can read the message, adjust, and retry
- A composable field component model that will allow reusable,
form-aware widgets to be introduced as the form grows
As patterns emerge across iterations (reusable field components, subform
composition, complex validation), they will be extracted and documented
as part of this reimplementation effort, or as part of the
reimplementation of other forms in the codebase. Whichever comes first.
Replaces the former AddressesDataList with a simple textarea as an intermediate step. The goal is to revisit the multi-value input later with a more fluent and accessible approach. Both IPv4 and IPv6 addresses are handled in a single field. Addresses without a prefix default to /24 for IPv4 and /64 for IPv6. The field label reflects the current requirement based on the selected methods, following the field labelling conventions in src/components/form/conventions.md (temporary file will be moved elsewhere later).
Gateway fields are only shown when the corresponding method is manual, which might suggest they are always required when visible. However, according to the NetworkManager documentation, the gateway is not mandatory even in manual mode: it is only meaningful when addresses are set, and can be replaced by an explicit default route. Following the conventions in src/components/form/conventions.md, fields that are conditionally shown but can still be left blank should carry the (optional) suffix to make that clear to the user. See: https://networkmanager.dev/docs/api/latest/settings-ip4-config.html
Introduces a reusable component for rendering form field labels with an optional suffix styled to be visually dimmer than the main label text. This makes the suffix clearly secondary for sighted users while keeping the full string accessible to screen readers as a single label.
Introduces a "Use custom DNS servers" checkbox that reveals a textarea for entering nameservers. When unchecked, an empty array is submitted. When checked, the field is shown and its value is submitted. The field value is preserved in form state when the checkbox is unchecked, so re-checking restores what the user previously typed. Validation will be added in a later commit. This establishes the checkbox opt-in as a pattern for advanced or rarely needed fields, documented in src/components/form/conventions.md.
Formerly named FormLabel but renamed in this commit to LabelText because it is a more accurate name due the fact that the component renders text content passed to a FormGroup label prop, not a label element itself. Adds a hidden prop that visually hides the text content while keeping it in the DOM. This is used for fields that have no visible label due to their context, such as the DNS textarea inside checkbox body. Keeping real DOM text is preferred over aria-label because it is able to be translated by browser tools and does not depend on ARIA support.
Adds a "Use custom DNS search domains" checkbox that reveals a textarea for entering search domains, following the same checkbox opt-in pattern as DNS servers.
Reverts the use of LabelText hidden for the DNS servers and DNS search domains textareas. PatternFly's FormGroup reserves visual space for the label area whenever a label prop is provided, even when its content is visually hidden, leaving an unwanted gap in the layout. Working around that with CSS overrides would be hacky and fragile for little practical benefit in an application that manages its own translations via _(). aria-label is used instead. It is widely supported and works correctly in this context.
The Checkbox body prop renders its content inside a span element, which is invalid HTML for block content like a FormGroup with a TextArea. Replaces it with a NestedContent sibling rendered conditionally when the checkbox is checked, which is both semantically correct and consistent with how nested content is handled elsewhere in the application.
…m (part 1) (#3300) This PR starts the reimplementation of the network connection form using [TanStack Form](https://tanstack.com/form/latest), replacing the previous ad-hoc form state management with a structured, library-backed approach. ## What is included In order to avoid an endless PR and make it easier to follow for review, the whole reimplementation will be addressed in multiple PRs against a feature branch. This first PR covers the following fields: - Connection name and interface - IPv4 and IPv6 method and gateway - IP addresses (single textarea for both protocols, with dynamic label reflecting the current requirement based on the selected methods) - DNS servers (hidden behind a checkbox opt-in) - DNS search domains (hidden behind a checkbox opt-in) Additionally, two files have been included as part of this PR: - `src/components/form/LabelText`: a reusable component that renders text content for a FormGroup label prop, with an optional styled suffix (e.g. "(optional)") and a hidden prop for fields that need an accessible label without visible text. - `src/components/form/conventions.md`: a set of form conventions documented as patterns arose, covering field visibility patterns, label suffixes, and accessibility guidance. It should be moved elsewhere after reaching the master branch, but kept in the newly created form namespace for now. The idea is to keep it up to date as the project evolves and form patterns that suit it well arise. ## What is deferred to follow-up PRs - **Field validation.** No client-side validation is done yet. The server acts as the validator via `onSubmitAsync`. Empty required fields, invalid addresses, and required DNS servers when checked will be added incrementally. - **Enhanced multi-value input.** IP addresses, DNS servers, and DNS search domains are currently plain textareas allowing values separated by space or new lines. These will be replaced with a more fluent, easy to understand/work with, and accessible multi-value input. - **Auto-generated connection name.** The name field has no default value yet. It will derive a suggestion from the selected interface and/or connection type. - **Type-specific subforms.** Bond, bridge, and VLAN configuration. - **Edition mode.** Once everything is in place, the form will be adapted to manage the edition of a connection too, which has some additional restrictions like Interface and Name not editable. - **Reusable TanStack field components.** As patterns stabilize, field components will be registered in `useAppForm` and shared across forms. ## Notes for reviewers The conventions document (`src/components/form/conventions.md`) is worth reading first, as it explains the reasoning behind field visibility and label choices, and will apply to all future form work across the application (on agreement, of course). _Changelog entry postponed for the final PR from feature branch against master branch._ --- Related to https://trello.com/c/rUEeqOkf (protected link)
Introduces `ChoiceField`, a generic TanStack Form-aware select component for mode/behavior selection. Registered in `fieldComponents` so it is accessed as `field.ChoiceField` inside `form.AppField` render props. Splits form contexts into `hooks/form-contexts.tsx` to avoid the circular import that would arise from field components importing `useFieldContext` while `hooks/form.tsx` imports those same components for registration.
Adds Pattern 5 (choice selector) and renumbers the former patterns 2–5 to make room for it. Reorders patterns from least to most intrusive and rewrites the "Combining patterns" and "Choosing the right pattern" sections accordingly.
Renders a protocol-specific IP configuration block using a three-level structure: mode selector (Default/Custom), method selector (Automatic/Manual), and the corresponding fields. Manual mode shows required addresses plus optional gateway and DNS. Automatic mode offers an opt-in checkbox for extra static settings on top of DHCP. Uses `useFormContext` following the TanStack Form composition guide, so it can be dropped into any `useAppForm`-backed form without prop-drilling. Field names are passed explicitly via `fieldNames`.
Replace the flat IPv4/IPv6 method selectors, the combined IP Addresses textarea, and the top-level "Use custom DNS servers" checkbox with two IpSettings components, one per protocol. Each manages its own mode (Default/Custom), method (Automatic/Manual), addresses, gateway, nameservers, and the opt-in "With extra IPv4/IPv6 settings" toggle. Wrap the form body in form.AppForm so child components can access the form context via useFormContext. The submit handler merges per-protocol addresses and nameservers into the flat arrays expected by the Connection constructor, including values only from protocols with active custom configuration. All IpSettings field labels are prefixed with the protocol name (e.g. "IPv4 Gateway" instead of "Gateway") so each label is self-sufficient when announced by a screen reader navigating outside the visual grouping. Sighted users benefit too: the prefix removes any ambiguity when both protocols are visible at once. See WCAG 2.4.6 (Headings and Labels): https://www.w3.org/WAI/WCAG21/Understanding/headings-and-labels.html The gateway field in DHCP+extra mode carries the suffix "(optional, ignored without a static IP)" to clarify that a gateway alone has no effect without at least one static address alongside it.
Replace the two-level Default/Custom mode + Auto/Manual method + "With
extra settings" checkbox structure with a single three-option selector:
Default, Automatic, and Manual.
- IpSettings now takes only three field names: mode, addresses, gateway
- Addresses are optional in Automatic mode and required in Manual mode
- Gateway is shown for both non-default modes; omitted at submit time
unless at least one address is present
- DNS servers moved back to the top level in ConnectionForm as a shared
checkbox+textarea
Most users choosing Automatic (DHCP) do not need to set static addresses or a gateway alongside it. Showing those fields upfront adds visual noise and may confuse users who are not aware that combining DHCP with static settings is even a valid configuration. A "Show advanced settings" toggle now appears alongside the mode selector in Automatic mode, hiding the extra fields until explicitly requested. Manual mode is unaffected and always shows addresses and gateway, since those are the point of choosing it. The submit handler only collects addresses and gateway for Automatic mode when the advanced toggle is enabled.
…pproach 2) Previous iterations either showed static address fields for all Automatic users (too much upfront complexity) or hid them behind a checkbox toggle alongside the selector (two controls where one should suffice). Both violated the principle of progressive disclosure. This approach keeps a single selector but adds a fourth option, Mixed, which makes the uncommon DHCP+static combination an explicit choice rather than a hidden extra. Users who just want DHCP pick Automatic and see nothing else. Users who need static addresses on top of DHCP pick Mixed and get exactly that. The right complexity is revealed only when the user actively asks for it. Descriptions do the heavy lifting: instead of hiding complexity behind a toggle, they guide the user toward the right choice, including a "not needed for most setups" nudge on Mixed. Each option carries a protocol-aware description where relevant: Automatic shows DHCP for IPv4 and SLAAC or DHCPv6 for IPv6, reflecting how NetworkManager's auto method behaves differently per protocol.
Replace the plain FormSelect-based interface field with two dedicated ChoiceField components for interface binding UI: - BindingModeSelector: wraps the binding mode selection (Unbound / By device name / By MAC address) with descriptions that clarify each option's effect on the connection. - DeviceSelector: picks a network device by interface name or MAC address; the non-selected identifier is shown as a styled description for context. Both components use useFormContext internally and are laid out side-by-side via Flex/FlexItem in ConnectionForm, with DeviceSelector appearing only when the mode is not Unbound (via form.Subscribe).
The Default option is dropped from IP settings. It represented a NetworkManager implementation detail (no method written to the profile) that most users would not understand. Automatic now covers that common case, with NetworkManager deciding how to configure the interface. Mixed is renamed to Advanced DHCP (IPv4) or Advanced Automatic (IPv6), making it clear it extends the automatic case rather than a separate alternative. Option descriptions are rewritten to be concise and neutral: no trailing periods, no user-targeting language, no protocol jargon. "Interface binding" renamed to "Device" and its options drop technical vocabulary in favor of plain language: Any, Chosen by name, and Chosen by MAC. The device picker that appears next to the binding selector gets a visually hidden label, since the selector already provides enough context.
The IPv4 and IPv6 mode selectors used different labels for the same option: "Advanced DHCP" and "Advanced Automatic". The distinction was technically accurate: IPv4 automatic addressing uses DHCP, while IPv6 uses SLAAC, making "DHCP" wrong for IPv6. Hence "Advanced Automatic". However, such asymmetry could raise the exact question it tried to avoid: why does one selector say DHCP and the other say Automatic? Both words describe the underlying mechanism, not the outcome, conflicting with the plain-language description style adopted for all other options. This commit changes both labels to "Advanced". The description still conveys the relationship to Automatic without encoding protocol-specific implementation details in the label.
…-components IpSettings, BindingModeSelector, and DeviceSelector previously used useFormContext(), which is designed for generic leaf field components and is deliberately untyped. Since these components render slices of a known form, withForm() is the correct fit. The mismatch forced "as any" casts on every field name and subscribe selector, silently bypassing TypeScript's checks and leaving field renames undetected at compile time. Rewriting the three components with withForm() removes all "as any" casts and restores full type safety. The form options were extracted from ConnectionForm using formOptions() and exported to allow sub-components spread it in their withForm() definition for type inference. Also, a convenience mergeFormDefaults helper has been added for handling the case where some defaults depend on runtime hook values and cannot be declared statically.
And use <Text srOnly> directly instead. HiddenLabel implied a <label> element but just rendered <Text srOnly>.
FlexItem with no props adds no value. Flex lays out its direct children as flex items regardless.
Rename the `template` prop to `sentence` and the `children` render prop argument from `label` to `text`. Broaden printf placeholder support from `%s` only to `%s`, `%d`, `%f`, and `%i` via a single inlined regex, covering the full set of common gettext specifiers.
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.
Adds `mergeArrays` option to concatenate array properties instead of replacing them based on precedence. When merging, arrays from both sources are concatenated with duplicates removed. Non-array properties continue following precedence rules. This allows merging network connections where config single values (method4, gateway4) must override system, but arrays (addresses, nameservers) should combine so users see existing system data even when config has empty arrays.
Updates ConnectionForm to properly display Advanced mode when config has no method but system already has addresses. This fixes the issue where editing a connection with undefined method but existing system addresses would incorrectly show Automatic instead of Advanced mode. On the other way around, shows Automatic (unset) instead of Advance when the method is "auto" but there are no addresses at all.
Simplifies connection name generation to only use the connection type, removing device-specific details (interface name, MAC address). Remove the no longer needed onChange listener to avoid unnecessary re-execution on every form field change.
When users enter an IP address without a CIDR prefix, the system now automatically appends a default value: /24 for IPv4 and /64 for IPv6. This normalization only applies to valid IP addresses; invalid input remains unchanged and is handled later by existing validation. Applying the prefix at this stage ensures users can immediately see the final value that will be saved, even if they did not specify a prefix manually.
When users enter IP addresses in the connection form without specifying a prefix (like /24), the system now adds one automatically using standard networking conventions: - 10.0.0.1: 10.0.0.1/8 (Class A) - 172.16.0.1: 172.16.0.1/16 (Class B) - 192.168.1.1: 192.168.1.1/24 (Class C) - 2001:db8::1: 2001:db8::1/64 (IPv6)
Replace hardcoded /24 and /64 prefixes with addDefaultIPPrefix utility which applies classful networking rules (Class A: /8, Class B: /16, Class C: /24, IPv6: /64).
Addresses now get default prefixes both when entered by users and when loaded from the backend, providing consistent UX. Removed the withPrefix defensive check at form submission since all addresses already have prefixes.
Show format examples for IP addresses, gateways, DNS servers, and DNS search domains. IP address fields explain that prefix is auto-added if omitted. Also fixed ArrayField to always show helper text instead of only when there are errors.
Replaces "unset" IP mode with explicit "auto" and introduces typed FormIpMode enum for better type safety and code clarity.
Introduces ADDRESS_REQUIRED_MODES constant to replace repetitive mode comparisons throughout the codebase.
Fixes a bug where IP addresses appeared twice when editing a connection that was previously saved with addresses. The issue occurred because extendCollection merges config and system connections with mergeArrays: true, concatenating addresses from both sources. After saving a connection, the same addresses exist in both config (user's explicit settings) and system (NetworkManager's active state), causing duplication when editing. Thus, this commit deduplicate addresses, nameservers, and DNS search domains in connectionToFormValues before populating the form. Add regression test to verify addresses are not duplicated when config and system have the same address.
# TL;DR
This bonus PR for the network connection form series includes polish
improvements and bug fixes.
The IP configuration modes have been restructured: the "unset" mode
(undefined method) has been replaced with "auto" (method.auto) as the
new default, and all modes have been renamed for clarity. Additional,
Manual mode now requires both addresses and gateway (gateway was
optional before).
The PR also fixes a bug where IP addresses, DNS servers, and search
domains appeared duplicated when editing saved connections, caused by
merging config and system arrays without deduplication. Additional
improvements include better connection name generation, proper IP mode
inference when editing connections, comprehensive translator comments
across all files, and code cleanup.
---
## The original description
A bonus PR for the network connection revamp series for addressing few
minor things found while reviewing notes.
### Minor Cleanup
Removes unnecessary props and type casts.
### Add missing translator comments
All touched and new files in this series has been reviewed for adding
missing `// TRANSLATORS:` comments. These provide translators with
context for format strings, abbreviations, UI roles, and otherwise
ambiguous strings.
### Introduce a new `Interpolate` component.
A utility component for rendering translated strings that include a
single placeholder, allowing arbitrary React content to be inserted via
a render prop.
#### Purpose
Some translated sentences need to include React elements (like links,
buttons, or styled text). While it's possible to manually split strings
or build sentences in fragments (the scattered approach across the
codebase), it makes translations harder to maintain and future updates
more error-prone. Thus, this small component:
* Centralizes the pattern in a reusable component.
* Prevents accidental fragmented translation units.
* Makes future improvements easier and safer.
* Closes an old debt that had been postponed, reducing ongoing risks and
disadvantages.
#### Usage example
```tsx
<Interpolate template={_("Or [remove all invalid entries.]")}>
{(label) => <Button onClick={clearInvalid}>{label}</Button>}
</Interpolate>
```
#### Supported placeholder
* `[label]`: text inside brackets is passed to `children` as `label`.
* `%s` / `%d` / `%f` / `%i`: standard gettext printf placeholders.
Only one placeholder per template is allowed by now. Strings without
placeholders render as plain text.
## 📝 Additions on 10th of April
### Add `mergeArrays` option to `extendCollection`
Adds a `mergeArrays` option to the `extendCollection` utility to
concatenate array properties instead of replacing them based on
precedence. It was needed in order to be able to compute and display the
IpAddresses and others from the system configuration when they are not
in config configuration. Reading the code could have a better insight of
that need.
### Infer IP mode from addresses when editing connections
Updates ConnectionForm to properly display "Advanced" mode when config
has no method but system already has addresses. Same in the other way
around, make the form able to display "Automatic" mode when method set
to auto but no addresses configured.
It fixes the issue where editing a connection with undefined method but
existing system addresses would incorrectly show Automatic instead of
Advanced mode.
### Simplify auto-generated connection name
Simplifies connection name generation to only use the connection type,
removing device-specific details (interface name, MAC address), which
produces a more human readable connection name.
## 📝 Additions on 14th of April
### IP Configuration Mode Improvements
**Mode Restructuring**
- Default mode changed from `"unset"` (undefined method) to `"auto"`
(method.auto)
- Renamed modes for clarity:
- "Default (automatic)" → "Auto": automatic configuration, no fields
shown
- "Explicit (automatic)" → "Advanced auto": automatic with required
addresses
- "Manual": static configuration with required addresses and gateway
**Gateway Requirements**
- Manual mode: gateway now **required** (was optional)
- Advanced auto mode: gateway remains optional
- Added validation with error messages: "IPv4/IPv6 gateway is required"
### Bug Fix: Deduplication When Editing Connections
Fixed a bug where IP addresses, DNS servers, and search domains appeared
twice when editing a connection that was previously saved with those
values.
**Root Cause**: `extendCollection` with `mergeArrays: true` concatenates
config and system arrays. After saving, the same values exist in both
sources, causing duplication on re-edit.
**Solution**: Deduplicate addresses, nameservers, and DNS search domains
in `connectionToFormValues()` using Radashi's `unique()` function.
**Test Coverage**: Added regression tests for all three deduplication
scenarios.
Merged
imobachgs
added a commit
that referenced
this pull request
Apr 14, 2026
Prepare to release version 20. * #3294 * #3295 * #3296 * #3297 * #3298 * #3299 * #3300 * #3301 * #3302 * #3303 * #3304 * #3305 * #3306 * #3307 * #3308 * #3309 * #3310 * #3311 * #3312 * #3313 * #3315 * #3316 * #3317 * #3318 * #3319 * #3320 * #3322 * #3323 * #3325 * #3326 * #3327 * #3329 * #3330 * #3331 * #3333 * #3334 * #3336 * #3338 * #3339 * #3342 * #3343 * #3349 * #3351 * #3352 * #3353 * #3354 * #3356 * #3357 * #3358 * #3359 * #3360 * #3361 * #3362 * #3363 * #3364 * #3365 * #3366 * #3367 * #3368 * #3371 * #3372 * #3373 * #3375 * #3376 * #3378 * #3379 * #3380 * #3381 * #3382 * #3385 * #3386
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Redesign network connection form, delivering a significantly improved user experience for creating and editing network connections in Agama.
The new form has been implemented using TanStack Form for robust field state management, provides independent IP configuration modes, integrated device binding options and better validation feedback among other aspects. It also defers form validation until submission to avoid interrupting users while typing.
For more details check all changes sent to the feature branch until now: