1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

#7084: Fix issue where hidden VLAN form fields were incorrectly included in the form submission

This commit is contained in:
thatmattlove
2021-09-01 11:41:35 -07:00
parent 6f94198934
commit a2eb0d80d2
5 changed files with 76 additions and 19 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -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<HTMLSelectElement>): Nullable<HTMLElem
return null;
}
/**
* Toggle visibility of the select element's container and disable the select element itself.
*
* @param element Select element.
* @param action 'show' or 'hide'
*/
function toggleVisibility<E extends Nullable<HTMLSelectElement>>(
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');
}
}

View File

@@ -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.<name>`
*/
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.
*