mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Fixes #7148: Handle array values when constructing API URLs
This commit is contained in:
parent
caa2813d0d
commit
113358f2de
@ -2,6 +2,7 @@
|
||||
|
||||
## v3.0.2 (FUTURE)
|
||||
* [#7131](https://github.com/netbox-community/netbox/issues/7131) - Fix issue where Site fields were hidden when editing a VLAN group
|
||||
* [#7148](https://github.com/netbox-community/netbox/issues/7148) - Fix issue where static query parameters with multiple values were not queried properly
|
||||
|
||||
---
|
||||
|
||||
|
BIN
netbox/project-static/dist/config.js
vendored
BIN
netbox/project-static/dist/config.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/config.js.map
vendored
BIN
netbox/project-static/dist/config.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/jobs.js
vendored
BIN
netbox/project-static/dist/jobs.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/jobs.js.map
vendored
BIN
netbox/project-static/dist/jobs.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/lldp.js
vendored
BIN
netbox/project-static/dist/lldp.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/lldp.js.map
vendored
BIN
netbox/project-static/dist/lldp.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js
vendored
BIN
netbox/project-static/dist/netbox.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js.map
vendored
BIN
netbox/project-static/dist/netbox.js.map
vendored
Binary file not shown.
BIN
netbox/project-static/dist/status.js
vendored
BIN
netbox/project-static/dist/status.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/status.js.map
vendored
BIN
netbox/project-static/dist/status.js.map
vendored
Binary file not shown.
@ -174,16 +174,6 @@ export class APISelect {
|
||||
this.preSorted = true;
|
||||
}
|
||||
|
||||
const emptyOption = base.getAttribute('data-empty-option');
|
||||
if (isTruthy(emptyOption)) {
|
||||
this.emptyOption = {
|
||||
text: emptyOption,
|
||||
value: '',
|
||||
};
|
||||
} else {
|
||||
this.emptyOption = EMPTY_PLACEHOLDER;
|
||||
}
|
||||
|
||||
if (hasUrl(base)) {
|
||||
const url = base.getAttribute('data-url') as string;
|
||||
this.url = url;
|
||||
@ -197,6 +187,16 @@ export class APISelect {
|
||||
this.disabledOptions = this.getDisabledOptions();
|
||||
this.disabledAttributes = this.getDisabledAttributes();
|
||||
|
||||
const emptyOption = base.getAttribute('data-empty-option');
|
||||
if (isTruthy(emptyOption)) {
|
||||
this.emptyOption = {
|
||||
text: emptyOption,
|
||||
value: '',
|
||||
};
|
||||
} else {
|
||||
this.emptyOption = EMPTY_PLACEHOLDER;
|
||||
}
|
||||
|
||||
this.slim = new SlimSelect({
|
||||
select: this.base,
|
||||
allowDeselect: true,
|
||||
@ -295,21 +295,18 @@ export class APISelect {
|
||||
newOptions = optionsIn.sort((a, b) => (a.text.toLowerCase() > b.text.toLowerCase() ? 1 : -1));
|
||||
}
|
||||
// Deduplicate options each time they're set.
|
||||
let deduplicated = uniqueByProperty(newOptions, 'value');
|
||||
const deduplicated = uniqueByProperty(newOptions, 'value');
|
||||
// Determine if the new options have a placeholder.
|
||||
const hasPlaceholder = typeof deduplicated.find(o => o.value === '') !== 'undefined';
|
||||
// Get the placeholder index (note: if there is no placeholder, the index will be `-1`).
|
||||
const placeholderIdx = deduplicated.findIndex(o => o.value === '');
|
||||
|
||||
if (hasPlaceholder && placeholderIdx < 0) {
|
||||
// If there is a placeholder but it is not the first element (due to sorting or other merge
|
||||
// issues), remove it from the options array and place it in front.
|
||||
deduplicated.splice(placeholderIdx);
|
||||
deduplicated = [this.emptyOption, ...deduplicated];
|
||||
}
|
||||
if (!hasPlaceholder) {
|
||||
// If there is no placeholder, add one to the front of the array.
|
||||
deduplicated = [this.emptyOption, ...deduplicated];
|
||||
if (hasPlaceholder && placeholderIdx >= 0) {
|
||||
// If there is an existing placeholder, replace it.
|
||||
deduplicated[placeholderIdx] = this.emptyOption;
|
||||
} else {
|
||||
// If there is not a placeholder, add one to the front.
|
||||
deduplicated.unshift(this.emptyOption);
|
||||
}
|
||||
this._options = deduplicated;
|
||||
this.slim.setData(deduplicated);
|
||||
|
@ -1,6 +1,8 @@
|
||||
import Cookie from 'cookie';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import type { Stringifiable } from 'query-string';
|
||||
|
||||
type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
||||
type ReqData = URLSearchParams | Dict | undefined | unknown;
|
||||
type SelectedOption = { name: string; options: string[] };
|
||||
@ -117,6 +119,30 @@ function getCsrfToken(): string {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constrict an object from a URL query param string, with all values as an array.
|
||||
*
|
||||
* @param params URL search query string.
|
||||
* @returns Constructed query object.
|
||||
*/
|
||||
function queryParamsToObject(params: string): Record<string, Stringifiable[]> {
|
||||
const result = {} as Record<string, Stringifiable[]>;
|
||||
const searchParams = new URLSearchParams(params);
|
||||
for (const [key, originalValue] of searchParams.entries()) {
|
||||
let value = [] as Stringifiable[];
|
||||
if (key in result) {
|
||||
value = [...value, ...result[key]];
|
||||
}
|
||||
if (Array.isArray(originalValue)) {
|
||||
value = [...value, ...originalValue];
|
||||
} else {
|
||||
value = [...value, originalValue];
|
||||
}
|
||||
result[key] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a NetBox URL that includes `settings.BASE_PATH` and enforces leading and trailing slashes.
|
||||
*
|
||||
@ -153,7 +179,7 @@ function buildUrl(destination: string): string {
|
||||
}
|
||||
const url = combined.join('/');
|
||||
// Construct an object from the URL search params so it can be re-serialized with the new URL.
|
||||
const query = Object.fromEntries(new URLSearchParams(search).entries());
|
||||
const query = queryParamsToObject(search);
|
||||
return queryString.stringifyUrl({ url, query });
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user