Repository: netbox-community/netbox

Issue:
"Enabled" flag is reset during editing of an interface if "802.1Q Mode" is changed
### NetBox version

v3.5.4

### Python version

3.10

### Steps to Reproduce

1. edit an interface of hardware or a VM
2. change the state of the `Enabled` flag, it doesn't matter if it is checked or not, it just needs to be changed
3. change the value for the `802.1Q Mode`

### Expected Behavior

The set value (checked or unchecked) for the `Enabled` flag should be preserved during editing of an interface and not be reset to the current actual state when changing anything.

### Observed Behavior

The state for the `Enabled` flag is reset to the current actual state when `802.1Q Mode` is changed.


Discussion:
> it doesn't matter if it is checked or not, it just needs to be changed

In my testing, I was only able to replicate this when _unchecking_ the enabled field (or any other checkbox field).

This is probably due to a caveat concerning checkbox fields. When the 802.1Q field value is changed, it triggers the form to re-render. All of the current field values are passed and populated in the newly-rendered form, however unticked checkboxes are omitted from this data. This causes checkbox fields to render with their original values (whether checked or unhcecked).

Ideally we should force the inclusion of unchecked checkbox fields as well.
htmx has a function `shouldInclude` to check if a input should be included which for a checkbox is only true if the checkbox is marked. https://github.com/bigskysoftware/htmx/blob/master/src/htmx.js#L2344C28-L2344C35 I was therefore not successful in forcing the inclusion of the not selected checkbox.

What I was able to get working was only replacing parts of the form with the help of [hx-select](https://htmx.org/attributes/hx-select/). To get this working i had to add an id to each [field-group](https://github.com/netbox-community/netbox/blob/7f22c6bf12e5e4e18691fe65973f6a33dab8d066/netbox/templates/htmx/form.html#L12C5-L12C35), extend the [HTMXSelect](https://github.com/netbox-community/netbox/blob/7f22c6bf12e5e4e18691fe65973f6a33dab8d066/netbox/utilities/forms/widgets/select.py#L51) to ad the `hx-select` attribute with the same value as hx-target and add a parameter to the call of [HTMXSelect in InterfaceForm](https://github.com/netbox-community/netbox/blob/7f22c6bf12e5e4e18691fe65973f6a33dab8d066/netbox/dcim/forms/model_forms.py#L1145) to only replace the 802.1q Switching filed Group.

This would work for the issue, as the whole 802.1q Group has no checkbox in it. However there could be cases where this would not work, for example if the form group which should be replaced has a checkbox in it which should be preserved.

How do you feel about this approach? If desired I can create a pr with this approach.

An other solution could be to tag all checkbox with [hx-preserve](https://htmx.org/attributes/hx-preserve/) to have htmx preserve them. However I was not able to figure out how to do this.

Resolving patch:
diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py
--- a/netbox/netbox/settings.py
+++ b/netbox/netbox/settings.py
@@ -355,6 +355,7 @@ def _setting(name, default=None):
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'django.contrib.humanize',
+    'django.forms',
     'corsheaders',
     'debug_toolbar',
     'graphiql_debug_toolbar',
@@ -430,6 +431,9 @@ def _setting(name, default=None):
     },
 ]
 
+# This allows us to override Django's stock form widget templates
+FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
+
 # Set up authentication backends
 if type(REMOTE_AUTH_BACKEND) not in (list, tuple):
     REMOTE_AUTH_BACKEND = [REMOTE_AUTH_BACKEND]


Test patch: