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)
|
## 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
|
* [#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;
|
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)) {
|
if (hasUrl(base)) {
|
||||||
const url = base.getAttribute('data-url') as string;
|
const url = base.getAttribute('data-url') as string;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
@ -197,6 +187,16 @@ export class APISelect {
|
|||||||
this.disabledOptions = this.getDisabledOptions();
|
this.disabledOptions = this.getDisabledOptions();
|
||||||
this.disabledAttributes = this.getDisabledAttributes();
|
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({
|
this.slim = new SlimSelect({
|
||||||
select: this.base,
|
select: this.base,
|
||||||
allowDeselect: true,
|
allowDeselect: true,
|
||||||
@ -295,21 +295,18 @@ export class APISelect {
|
|||||||
newOptions = optionsIn.sort((a, b) => (a.text.toLowerCase() > b.text.toLowerCase() ? 1 : -1));
|
newOptions = optionsIn.sort((a, b) => (a.text.toLowerCase() > b.text.toLowerCase() ? 1 : -1));
|
||||||
}
|
}
|
||||||
// Deduplicate options each time they're set.
|
// 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.
|
// Determine if the new options have a placeholder.
|
||||||
const hasPlaceholder = typeof deduplicated.find(o => o.value === '') !== 'undefined';
|
const hasPlaceholder = typeof deduplicated.find(o => o.value === '') !== 'undefined';
|
||||||
// Get the placeholder index (note: if there is no placeholder, the index will be `-1`).
|
// Get the placeholder index (note: if there is no placeholder, the index will be `-1`).
|
||||||
const placeholderIdx = deduplicated.findIndex(o => o.value === '');
|
const placeholderIdx = deduplicated.findIndex(o => o.value === '');
|
||||||
|
|
||||||
if (hasPlaceholder && placeholderIdx < 0) {
|
if (hasPlaceholder && placeholderIdx >= 0) {
|
||||||
// If there is a placeholder but it is not the first element (due to sorting or other merge
|
// If there is an existing placeholder, replace it.
|
||||||
// issues), remove it from the options array and place it in front.
|
deduplicated[placeholderIdx] = this.emptyOption;
|
||||||
deduplicated.splice(placeholderIdx);
|
} else {
|
||||||
deduplicated = [this.emptyOption, ...deduplicated];
|
// If there is not a placeholder, add one to the front.
|
||||||
}
|
deduplicated.unshift(this.emptyOption);
|
||||||
if (!hasPlaceholder) {
|
|
||||||
// If there is no placeholder, add one to the front of the array.
|
|
||||||
deduplicated = [this.emptyOption, ...deduplicated];
|
|
||||||
}
|
}
|
||||||
this._options = deduplicated;
|
this._options = deduplicated;
|
||||||
this.slim.setData(deduplicated);
|
this.slim.setData(deduplicated);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import Cookie from 'cookie';
|
import Cookie from 'cookie';
|
||||||
import queryString from 'query-string';
|
import queryString from 'query-string';
|
||||||
|
|
||||||
|
import type { Stringifiable } from 'query-string';
|
||||||
|
|
||||||
type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
type Method = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
||||||
type ReqData = URLSearchParams | Dict | undefined | unknown;
|
type ReqData = URLSearchParams | Dict | undefined | unknown;
|
||||||
type SelectedOption = { name: string; options: string[] };
|
type SelectedOption = { name: string; options: string[] };
|
||||||
@ -117,6 +119,30 @@ function getCsrfToken(): string {
|
|||||||
return value;
|
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.
|
* 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('/');
|
const url = combined.join('/');
|
||||||
// Construct an object from the URL search params so it can be re-serialized with the new URL.
|
// 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 });
|
return queryString.stringifyUrl({ url, query });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user