diff --git a/docs/release-notes/version-3.0.md b/docs/release-notes/version-3.0.md index 341cd1ac4..58bc4a87a 100644 --- a/docs/release-notes/version-3.0.md +++ b/docs/release-notes/version-3.0.md @@ -14,6 +14,7 @@ * [#7082](https://github.com/netbox-community/netbox/issues/7082) - Avoid exception when referencing invalid content type in table * [#7083](https://github.com/netbox-community/netbox/issues/7083) - Correct labeling for VM memory attribute * [#7084](https://github.com/netbox-community/netbox/issues/7084) - Fix KeyError exception when editing access VLAN on an interface +* [#7084](https://github.com/netbox-community/netbox/issues/7084) - Fix issue where hidden VLAN form fields were incorrectly included in the form submission * [#7089](https://github.com/netbox-community/netbox/issues/7089) - Fix ContentTypeFilterSet not filtering on q filter * [#7090](https://github.com/netbox-community/netbox/issues/7090) - Fix Cable Bulk Edit Form - allow decimal input on Length field * [#7091](https://github.com/netbox-community/netbox/issues/7091) - Ensure API requests from the UI are aware of `BASE_PATH` diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index e9ea8ddbf..c64df2e26 100644 Binary files a/netbox/project-static/dist/netbox.js and b/netbox/project-static/dist/netbox.js differ diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 1d3380868..c9deea0b1 100644 Binary files a/netbox/project-static/dist/netbox.js.map and b/netbox/project-static/dist/netbox.js.map differ diff --git a/netbox/project-static/src/forms/vlanTags.ts b/netbox/project-static/src/forms/vlanTags.ts index 03ec73e60..4ad97c363 100644 --- a/netbox/project-static/src/forms/vlanTags.ts +++ b/netbox/project-static/src/forms/vlanTags.ts @@ -1,4 +1,4 @@ -import { all, getElement, resetSelect, toggleVisibility } from '../util'; +import { all, getElement, resetSelect, toggleVisibility as _toggleVisibility } from '../util'; /** * Get a select element's containing `.row` element. @@ -14,6 +14,38 @@ function fieldContainer(element: Nullable): Nullable>( + element: E, + action: 'show' | 'hide', +): void { + // Find the select element's containing element. + const parent = fieldContainer(element); + if (element !== null && parent !== null) { + // Toggle container visibility to visually remove it from the form. + _toggleVisibility(parent, action); + // Create a new event so that the APISelect instance properly handles the enable/disable + // action. + const event = new Event(`netbox.select.disabled.${element.name}`); + switch (action) { + case 'hide': + // Disable the native select element and dispatch the event APISelect is listening for. + element.disabled = true; + element.dispatchEvent(event); + break; + case 'show': + // Enable the native select element and dispatch the event APISelect is listening for. + element.disabled = false; + element.dispatchEvent(event); + } + } +} + /** * Toggle element visibility when the mode field does not have a value. */ @@ -29,7 +61,7 @@ function handleModeNone(): void { resetSelect(untaggedVlan); resetSelect(taggedVlans); for (const element of elements) { - toggleVisibility(fieldContainer(element), 'hide'); + toggleVisibility(element, 'hide'); } } } @@ -46,9 +78,9 @@ function handleModeAccess(): void { if (all(elements)) { const [taggedVlans, untaggedVlan, vlanGroup] = elements; resetSelect(taggedVlans); - toggleVisibility(fieldContainer(vlanGroup), 'show'); - toggleVisibility(fieldContainer(untaggedVlan), 'show'); - toggleVisibility(fieldContainer(taggedVlans), 'hide'); + toggleVisibility(vlanGroup, 'show'); + toggleVisibility(untaggedVlan, 'show'); + toggleVisibility(taggedVlans, 'hide'); } } @@ -63,9 +95,9 @@ function handleModeTagged(): void { ]; if (all(elements)) { const [taggedVlans, untaggedVlan, vlanGroup] = elements; - toggleVisibility(fieldContainer(taggedVlans), 'show'); - toggleVisibility(fieldContainer(vlanGroup), 'show'); - toggleVisibility(fieldContainer(untaggedVlan), 'show'); + toggleVisibility(taggedVlans, 'show'); + toggleVisibility(vlanGroup, 'show'); + toggleVisibility(untaggedVlan, 'show'); } } @@ -81,9 +113,9 @@ function handleModeTaggedAll(): void { if (all(elements)) { const [taggedVlans, untaggedVlan, vlanGroup] = elements; resetSelect(taggedVlans); - toggleVisibility(fieldContainer(vlanGroup), 'show'); - toggleVisibility(fieldContainer(untaggedVlan), 'show'); - toggleVisibility(fieldContainer(taggedVlans), 'hide'); + toggleVisibility(vlanGroup, 'show'); + toggleVisibility(untaggedVlan, 'show'); + toggleVisibility(taggedVlans, 'hide'); } } diff --git a/netbox/project-static/src/select/api/apiSelect.ts b/netbox/project-static/src/select/api/apiSelect.ts index a10f646d2..fe7c218a3 100644 --- a/netbox/project-static/src/select/api/apiSelect.ts +++ b/netbox/project-static/src/select/api/apiSelect.ts @@ -320,6 +320,7 @@ export class APISelect { this.slim.slim.multiSelected.container.setAttribute('disabled', ''); } } + this.slim.disable(); } /** @@ -335,6 +336,7 @@ export class APISelect { this.slim.slim.multiSelected.container.removeAttribute('disabled'); } } + this.slim.enable(); } /** @@ -357,6 +359,11 @@ export class APISelect { this.fetchOptions(this.more, 'merge'), ); + // When the base select element is disabled or enabled, properly disable/enable this instance. + this.base.addEventListener(`netbox.select.disabled.${this.name}`, event => + this.handleDisableEnable(event), + ); + // Create a unique iterator of all possible form fields which, when changed, should cause this // element to update its API query. // const dependencies = new Set([...this.filterParams.keys(), ...this.pathValues.keys()]); @@ -578,6 +585,23 @@ export class APISelect { Promise.all([this.loadData()]); } + /** + * Event handler to be dispatched when the base select element is disabled or enabled. When that + * occurs, run the instance's `disable()` or `enable()` methods to synchronize UI state with + * desired action. + * + * @param event Dispatched event matching pattern `netbox.select.disabled.` + */ + private handleDisableEnable(event: Event): void { + const target = event.target as HTMLSelectElement; + + if (target.disabled === true) { + this.disable(); + } else if (target.disabled === false) { + this.enable(); + } + } + /** * When the API returns an error, show it to the user and reset this element's available options. *