diff --git a/docs/release-notes/version-3.0.md b/docs/release-notes/version-3.0.md index 0d6e4e659..0e30487e3 100644 --- a/docs/release-notes/version-3.0.md +++ b/docs/release-notes/version-3.0.md @@ -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 --- diff --git a/netbox/project-static/dist/config.js b/netbox/project-static/dist/config.js index cf1022589..0e701fc85 100644 Binary files a/netbox/project-static/dist/config.js and b/netbox/project-static/dist/config.js differ diff --git a/netbox/project-static/dist/config.js.map b/netbox/project-static/dist/config.js.map index 5f27e84a6..63379ab42 100644 Binary files a/netbox/project-static/dist/config.js.map and b/netbox/project-static/dist/config.js.map differ diff --git a/netbox/project-static/dist/jobs.js b/netbox/project-static/dist/jobs.js index 3faf4b7ec..a2d9ead62 100644 Binary files a/netbox/project-static/dist/jobs.js and b/netbox/project-static/dist/jobs.js differ diff --git a/netbox/project-static/dist/jobs.js.map b/netbox/project-static/dist/jobs.js.map index e07a4157d..c1e2ac34b 100644 Binary files a/netbox/project-static/dist/jobs.js.map and b/netbox/project-static/dist/jobs.js.map differ diff --git a/netbox/project-static/dist/lldp.js b/netbox/project-static/dist/lldp.js index 86adb3db6..a704b158d 100644 Binary files a/netbox/project-static/dist/lldp.js and b/netbox/project-static/dist/lldp.js differ diff --git a/netbox/project-static/dist/lldp.js.map b/netbox/project-static/dist/lldp.js.map index 028c35995..ab5d4295a 100644 Binary files a/netbox/project-static/dist/lldp.js.map and b/netbox/project-static/dist/lldp.js.map differ diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 1cba69a9d..92ffda9de 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 23f292a66..678ca7255 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/dist/status.js b/netbox/project-static/dist/status.js index 2f3c2f762..f4e64b5ef 100644 Binary files a/netbox/project-static/dist/status.js and b/netbox/project-static/dist/status.js differ diff --git a/netbox/project-static/dist/status.js.map b/netbox/project-static/dist/status.js.map index fc612cec8..d2c1a9c49 100644 Binary files a/netbox/project-static/dist/status.js.map and b/netbox/project-static/dist/status.js.map differ diff --git a/netbox/project-static/src/select/api/apiSelect.ts b/netbox/project-static/src/select/api/apiSelect.ts index d88e73f11..11576c53f 100644 --- a/netbox/project-static/src/select/api/apiSelect.ts +++ b/netbox/project-static/src/select/api/apiSelect.ts @@ -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); diff --git a/netbox/project-static/src/util.ts b/netbox/project-static/src/util.ts index 9103a7b01..278ccc3e5 100644 --- a/netbox/project-static/src/util.ts +++ b/netbox/project-static/src/util.ts @@ -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 { + const result = {} as Record; + 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 }); }