Explorar el Código

Fixes #7148: Handle array values when constructing API URLs

thatmattlove hace 4 años
padre
commit
113358f2de

+ 1 - 0
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
 
 ---
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/config.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/config.js.map


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/jobs.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/jobs.js.map


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/lldp.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/lldp.js.map


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/netbox.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/netbox.js.map


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/status.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
netbox/project-static/dist/status.js.map


+ 17 - 20
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);

+ 27 - 1
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<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 });
 }
 

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio